PC Easy Weblog

mai 18, 2009

SQL Server – UPDATE de lignes d’une table par un SELECT

Filed under: Développement, Utilitaires — Étiquettes : , , , — trucmuche92 @ 9:26

Pour ceux qui comme moi ne se rappelaient plus comment on mettait à jour une table à partir d’un SELECT voici un mémo :

Le principe est de se représenter dans un premier temps un SELECT (multi-table) qui contient la table que l’on veut mettre à jour.

L’exemple ci-dessous mettra a jour le champ-flag ACTIF d’une table PRODUIT en fonction du champ VISIBLE du d’une table d’association CATALOGUE_PRODUIT dans lequel il est.

1 – Représentation en SELECT

select p.pro_actif, c.pro_visible, etc…
from PRODUIT p
inner join  CATALOGUE_PRODUIT c
on p.pro_codesap = c.pro_codesap

2 – Pour la commande d’UPDATE, on dégage la partie SELECT pour la remplacer par la syntaxe UPDATE

update p set p.pro_actif = c.pro_visible, p.datmaj = getdate()
from PRODUIT p
inner join  CATALOGUE_PRODUIT c
on p.pro_codesap = c.pro_codesap

On remarquera l’importance du raccourci (alias) p pour la table PRODUIT qui est représentée à la fois pour la table du SELECT et la table de l’UPDATE.

Remarque : on ne peut mettre à jour que les champs d’une table.

avril 24, 2009

CSharp – Evennement & Delegate & EventArgs, pour que ce soit clair

Filed under: Développement, Utilitaires — Étiquettes : , — trucmuche92 @ 11:02

Voici pas à pas les éléments à mettre en place pour exploiter de l’évennementiel depuis un UserControl.
L’exemple fournie illustre un UserControl qui est inclus dans les éléments d’une liste (un Datalist par exemple), ce Usercontrol déclenche un évennement lorsque l’utilisateur ajoute une quantité à son panier (dans le cas d’une boutioque en ligne).

1 – Définir un évennement (=définir un Delegate)

On créée un Delegate que l’on nomme UCMAJPanierEventHandler.
Un Delegate se situe au même niveau qu’une Class, il n’est donc pas à mettre en place à l’intérieur d’une Class ou d’un UserControl

Version Basique :

public delegate void UCMAJPanierEventHandler(object sender, EventArgs e);

object sender et EventArgs e sont la signature de base.
Si lors de l’évennement on veut transmettre des information supplémentaires, on peut créer une classe qui hérite de la classe EventArgs :

 public class UCMAJPanierEventArgs : EventArgs
 {
      public string pro_codesap;
       public string quantite;
 }

Dès lors la définition du Delegate deviendra :

public delegate void UCMAJPanierEventHandler(object sender, UCMAJPanierEventArgs e);

2 – Ajouter à son controle la possibilité d’utiliser ce Delegate en tant que Sender

 public partial class UCDetailProduit : System.Web.UI.UserControl
 {
      public event UCMAJPanierEventHandler UCMajPanier;
      ...
      ...
 }

On déclare donc un événement du type UCMAJPanierEventHandler, et au même titre qu’une propriété (exemple string), on lui donne un Nom (UCMajPanier)
Pour être accessible aux autres Controles, Pages, il doit être Public.

Pour « Raiser » l’Evt, la commande est this.UCMajPanier(this, args) où args est l’objet qui supporte les arguments que l’on veut envoyer avec l’événement.
Il est nécessaire de tester préalablement si L’événement est branché par un Controle « receveur » sinon cela génère une exception d’où if (this.UCMajPanier != null).

public partial class UCDetailProduit : System.Web.UI.UserControl
 {
    public event UCMAJPanierEventHandler UCMajPanier;
    ...
    ...
    protected void btn_ajouter_panier_Click(object sender, EventArgs e)
    {
        if (this.UCMajPanier != null)
        {
            UCMAJPanierEventArgs args = new UCMAJPanierEventArgs();
            args.pro_codesap = hidden_prd_code.Text;
            args.quantite = txt_qte.Text;
            this.UCMajPanier(this, args);
        }
    }
    ...
    ...
 }

3 – Connexion du Sender au Receveur

Lors de la génération du Controle Sender dans le Datalist, il faut créer une « connexion » entre le Sender et celui qui va gérer la réception de l’évennement.
Pour un Datalist, le moment idéal est l’evennement Item_Created :

public partial class prod_liste System.Web.UI.Page
{
....
 ....
protected void dlProduits_ItemCreated(object sender, DataListItemEventArgs e)
{
    if ((e.Item.ItemType == ListItemType.AlternatingItem) || (e.Item.ItemType == ListItemType.Item))
    {
        UCDetailProduit dp = e.Item.FindControl("UCDetailProduit") as UCDetailProduit;
        if (dp != null)
        {
           dp.UCMajPanier += new UCMAJPanierEventHandler(ProduitAjouterAuPanier);
        }
    }
    }
    ....
    ....
    protected void ProduitAjouterAuPanier(object sender, UCMAJPanierEventArgs e)
    {
        DataService.UpdatePanier(e.pro_codesap, e.quantite);
    }
    }

mars 3, 2009

SQL Server – ROW_NUMBER(), l’équivalent du ROWNUM d’Oracle

Filed under: Développement — Étiquettes : — trucmuche92 @ 8:54

Avec SQL Server 2005, on cette nouvelle fonction qui permet de numéroté d’une façon distinct chaque ligne : ROW_NUMBER()

Prenons par exemple le contenu de la table suivante :

select codex, commune from villes
codex commune
----- --------------------
02300 ABBECOURT
20243 ABBAZIA
25320 ABBANS DESSOUS
25440 ABBANS DESSUS
44170 ABBARETZ
54610 ABAUCOURT
55130 ABAINVILLE
55400 ABAUCOURT HAUTECOURT
59268 ABANCOURT
60220 ABANCOURT
60430 ABBECOURT
64460 AAST

Il s’agit donc de numéroter chaque ligne, mais ROW_NUMBER() nécessite de préciser sur quelle champ on défini l’ordre de numérotation.
Aussi la syntaxe exacte pour le champ qui reçoit la numérotation est  :

ROW_NUMBER() over(order by champ)

Avec le jeu de données ci-dessus, on pourra numéroter les lignes par ordre croissant de commune :

select codex, commune, row_number() over(order by commune) as num
from villes 
codex commune              num
----- -------------------- --------------------
64460 AAST                 1
55130 ABAINVILLE           2
59268 ABANCOURT            3
60220 ABANCOURT            4
54610 ABAUCOURT            5
55400 ABAUCOURT HAUTECOURT 6
25320 ABBANS DESSOUS       7
25440 ABBANS DESSUS        8
44170 ABBARETZ             9
20243 ABBAZIA              10
02300 ABBECOURT            11
60430 ABBECOURT            12

On remarquera la fonction ROW_NUMBER() filera toujours un numéro distinct, même si le champ sur lequel est poser la numérotation est le même d’une ligne à l’autre (commune ABANCOURT), il s’agit donc bien d’un numéro de ligne.

On pourra conserver la numérotation ci dessus, mais en présentant les données ordonnées par code postale

select codex, commune, row_number() over(order by commune) as num
from villes order by codex
codex commune              num
----- -------------------- --------------------
02300 ABBECOURT            11
20243 ABBAZIA              10
25320 ABBANS DESSOUS       7
25440 ABBANS DESSUS        8
44170 ABBARETZ             9
54610 ABAUCOURT            5
55130 ABAINVILLE           2
55400 ABAUCOURT HAUTECOURT 6
59268 ABANCOURT            3
60220 ABANCOURT            4
60430 ABBECOURT            12
64460 AAST                 1

Ca c’est interressant !

Pour aller plus loin :

– on peut compléter la partie order by par des champs complémentaires :

select codex, dpt, commune,
row_number() over(order by Dpt asc, commune desc) as num
from villes

– ROW_NUMBER() a aussi son petit frère RANK() qui effectue un classement :

select codex, commune, rank() over(order by commune) as num
from villes order by commune
codex commune              num
----- -------------------- --------------------
64460 AAST                 1
55130 ABAINVILLE           2
59268 ABANCOURT            3
60220 ABANCOURT            3
54610 ABAUCOURT            5
55400 ABAUCOURT HAUTECOURT 6
25320 ABBANS DESSOUS       7
25440 ABBANS DESSUS        8
44170 ABBARETZ             9
20243 ABBAZIA              10
02300 ABBECOURT            11
60430 ABBECOURT            11

février 27, 2009

SQL Server – Tableau croisé oui, dynamique non

Filed under: Développement — Étiquettes : , — trucmuche92 @ 9:12

MS Access fournie une commande SQL qui permet de faire des requêtes SELECT de type tableau croisé dynamique (via la commande TRANSFORM). Dans ce cas, on est bien présence d’un tableau dynamiqe car le nombre de colonnes généré est dynamique en fonction des enregistrements du jeu de résultat.

Pour SQL Server, depuis sa version 2005, on a la syntaxe PIVOT qui permet de créer un tableau croisé à partir d’une table, en revanche pour ce qui est du dynamique, c’est pas encore ça.

En effet, il faut préciser les valeurs que prendront les colonnes, illustration :

On a une table cde_entete

3 champs-propriété : cde_liv_civilite, cde_status, cde_mode_liv

un champs numérique : cde_mnt_ht (celui qui aura l’agregat)

On veut un tableau croisé avec les données de la colonne « Mode livraison » (cde_mode_liv) en colonne :

SELECT
cde_liv_civilite,
cde_status,
SUM([1]) AS "avion",
SUM([2]) AS "train"
FROM  cde_entete
PIVOT ( SUM(cde_mnt_ht)
        FOR cde_mode_liv IN ([1], [2])
      ) AS xxx
GROUP BY cde_liv_civilite, cde_status

Pour comprendre, il faut prendre la syntaxe ci-dessus comme un SELECT traditionnel où xxx transforme la table cde_entete avec les valeurs du champ cde_mode_liv en tant que colonne.

Le blème, c’est que ces valeurs doivent être explicitement définies « IN ([1], [2])« , et c’est là qu’on perds l’aspect dynamique.

En revanche, là où ça peut être interressant c’est quand veut un resultset d’indicateurs très variés pour lesquels il nécessiterait d’effectuer de multiple jointures.
L’astuce résiderait à créer un resultset par une série de requêtes UNION dont 2 colonnes pivoteraient au final.

1 – Obtention d’indicateurs et de dimensions depuis plusieurs sourcing

        --1ere sourcing
        select
            year(dt_record) as ANNEE,
            'EMPLOYE' as DIMENSION,
            count(cd_employee) as VALEUR
            from RESOURCES group by year(dt_record)

    UNION
        --2ème sourcing
        select
            year(dt_planning) as ANNEE,
            'BUDGET' as DIMENSION,
            sum (AMOUNT) as VALEUR
            from BUD group by year(dt_planning)

    UNION
        --3ème sourcing
        select
            year(dt_sale) as ANNEE,
            'CA' as DIMENSION,
            sum (SALES) as VALEUR
            from PRODUCTS group by year(dt_sale)

2 – Le résultat de l’UNION sans le PIVOT :

ANNEE       DIMENSION VALEUR
----------- --------- -----------
2006        BUDGET    50000
2007        BUDGET    55000
2008        BUDGET    60000
2005        CA        100000
2006        CA        110000
2007        CA        55
2007        CA        66
2007        CA        120000
2005        EMPLOYE   80
2006        EMPLOYE   86
2007        EMPLOYE   90
2008        EMPLOYE   91

3 – En passant le PIVOT comme ceci…

SELECT
ANNEE,
SUM([EMPLOYE]) AS "Nbr Employés",
SUM([BUDGET]) AS "Budget planifié",
SUM([CA]) AS "Chiffre d'affaire"
FROM (

        --1ere sourcing
        select
            year(dt_record) as ANNEE,
            'EMPLOYE' as DIMENSION,
            count(cd_employee) as VALEUR
            from RESOURCES group by year(dt_record)

    UNION
        --2ème sourcing
        select
            year(dt_planning) as ANNEE,
            'BUDGET' as DIMENSION,
            sum (AMOUNT) as VALEUR
            from BUD group by year(dt_planning)

    UNION
        --3ème sourcing
        select
            year(dt_sale) as ANNEE,
            'CA' as DIMENSION,
            sum (SALES) as VALEUR
            from PRODUCTS group by year(dt_sale)

) MES_UNIONS
PIVOT ( SUM(VALEUR)
        FOR DIMENSION IN ([EMPLOYE], [BUDGET], [CA])
      ) AS bidon
GROUP BY ANNEE

4 – Résultat final :

ANNEE       Nbr Employés Budget planifié Chiffre d'affaire
----------- ------------ --------------- -----------------
2005        80                           100000
2006        86           50000           110000
2007        90           55000           120121
2008        91           60000

Cette méthode est très utile pour du reporting par exemple, et évite d’avoir recours à de multiples jointure externes.

SQL Server – Le cas du Case pour une comparaison

Filed under: Développement — Étiquettes : , — trucmuche92 @ 7:48

En SQL Server, l »utilisation de la syntaxe Case … When … When…else…end est bien utile quand on veut inclure un test dans une requête SELECT :

Exemple :

select nom, prenom, 
case civ 
when 1 then 'Monsieur'
when 2 then 'Madame'
else 'Non mentionné' end as civilite
from employes

Il arrive parfois que le test a effectuer ne s’appuie pas sur une égalité, mais sur une comparaison, la syntaxe est particulière et est la suivante :

select nom, prenom,
case 
        when LastActivityDate < '2008-01-01' then 'Très Longtemps'
        when LastActivityDate < '2008-07-01' then 'Longtemps'
        else 'Récement' end as "Dernère visite"
from aspnet_users

En fait la syntaxe peut paraître différente, mais pas pour tout le monde car les 2 commandes suivantes sont les mêmes et sont valides :

select nom, prenom, case civ 
                    when 1 then 'Monsieur'
                    when 2 then 'Madame'
                    else 'Non mentionné' 
                    end as civilite
from employes

select nom, prenom, case
                    when civ=1 then 'Monsieur' 
                    when civ=2 then 'Madame' 
                    else 'Non mentionné'
                    end as civilite
from employes

février 2, 2009

Ajax – Animation de traitement serveur

Filed under: Développement — Étiquettes : — trucmuche92 @ 9:01

preloaders_net

Preloader est un petit site qui permet de concevoir rapidement des animations de traitement du genre Ajax à partir de quelques modèles définis.

Quelques exemples :

21243639

Les modèles sont plutôt chouette, à bookmarker !!

janvier 3, 2009

Configurer ASP.NET, Visual Studio et IIS

Filed under: Développement — trucmuche92 @ 1:50

A chaque fois que je monte une machine de dev pour faire tourner un site web en asp.net avec IIS, il y a une config à faire que j’oublie à chaque fois, alors cette fois-ci, je blog l’affaire.

Symptôme : « the web application you are attempting on this web server is currently unavailable ».
Solution :

1 – Si IIS a été installé après le framework (ou l’inverse, je sais plus), exécuter la commande suivante dans une fenêtre DOS :

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis /i

Cela a pour effet mettre à jour IIS avec la version de asp.net.

2 – Dans les propriétés du site Web (côté IIS) s’assurer du paramétrage suivant :

  • Onglet ASP.NET / Sélectionner dans la liste déroulante  la bonne version de ASP.NET
  • Onglet Sécurité de répertoire / Bouton Modifier / Cocher Authentification intégrée Windows

3 – Ajouter l’utilisateur aspnet dans la liste du groupe Administrateurs
Panneau de configuration / Outils d’administration / Gestion de l’ordinateur / Utilisateurs et groupes locaux / Groupes /  Administrateurs / Ajouter / Saisir aspnet / Vérifier les noms / OK

4 – Re-démarrer le site (ou le pc, en fait je ne sais plus exactement ce que j’ai fais, mais ça a marché :))

Et bien sûre :

IIS / Onglet Documents, la liste des documents par défaut doit contenir le nom d’une page du site.
Visual studio / Le site web doit être configuré pour utiliser IIS et non plus le server web intégré à Visual Studio (via les propriétés du projet, onglet Web, Use IIS Web Server)

Créez un site Web ou un blog gratuitement sur WordPress.com.