IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Toutes les nouveautés de MS SQL Server 2005


précédentsommairesuivant

II. Améliorations apportées au langage SQL

Voici une liste que j'espère suffisamment exhaustive des nouveautés de MS SQL Server 2005 et terme de « pur » langage SQL…

II-A. Jointures externes (norme SQL 1992)


Excellente nouvelle : les jointures externes avec une syntaxe propre à SQL server et rendant des résultats souvent faux, ne sont désormais plus acceptées nativement. Cette nouvelle ne va pas réjouir un certain nombre de développeurs et de DBA qui se la sont « couler douce » depuis une décennie… Les jointures externes normatives sont dans la norme depuis 1992 et ont commencé à être supportées par SQL Server version 6.5. MS a mis en garde ses utilisateurs depuis la version 2000 qu'il était nécessaire d'utiliser les jointures normatives à base de LEFT, RIGHT ou FULL OUTER JOIN parce qu'elles ne seraient plus supportées dans les versions futures…

Le message d'erreur est alors le suivant :

Msg 4147, Level 15, State 1, Line …
The query uses non-ANSI outer join operators (« *= » or « =* »). To run this query without modification, please set the compatibility level for current database to 80 or lower, using stored procedure sp_dbcmptlevel. It is strongly recommended to rewrite the query using ANSI outer join operators (LEFT OUTER JOIN, RIGHT OUTER JOIN). In the future versions of SQL Server, non-ANSI join operators will not be supported even in backward-compatibility modes.

II-B. Opérateur EXCEPT et INTERSECT (SQL:1992)



Dorénavant, SQL Server se conforme à la norme et propose les opérateurs ensemblistes EXCEPT (différence) et INTERSECT (intersection). Cependant, et comme c'est le cas de l'actuel UNION, ces trois opérateurs n'implémentent pas le prédicat USING.

Exemple pour la différence :

Avec les tables :
Sélectionnez
CREATE TABLE MACHINE 
(MAC_NOM VARCHAR(12)) 

CREATE TABLE OBJET 
(OBJ_NOM VARCHAR(12))
Et les données :
Sélectionnez
INSERT INTO MACHINE VALUE('Moto') 
INSERT INTO MACHINE VALUE('Perçeuse') 
INSERT INTO MACHINE VALUE('Avion') 
INSERT INTO MACHINE VALUE('Ventilateur') 
INSERT INTO MACHINE VALUE('Réveil') 

INSERT INTO OBJET VALUE('Moto') 
INSERT INTO OBJET VALUE('Assiette') 
INSERT INTO OBJET VALUE('Livre') 
INSERT INTO OBJET VALUE('Table') 
INSERT INTO OBJET VALUE('Perçeuse')
Avant SQL Server 2005
Sélectionnez
SELECT OBJ_NOM 
FROM   T_OBJET 
WHERE  OBJ_NOM NOT IN (SELECT MAC_NOM 
                       FROM   T_MACHINE)
Ou bien
Sélectionnez
SELECT O.OBJ_NOM 
FROM   T_OBJET O 
       LEFT OUTER JOIN T_MACHINE M 
            ON O.OBJ_NOM = M.MAC_NOM 
GROUP BY O.OBJ_NOM 
HAVING COUNT(M.MAC_NOM) = 0 

OBJ_NOM 
---------------- 
ASSIETTE 
LIVRE 
TABLE
Avec SQL Server 2005
Sélectionnez
SELECT OBJ_NOM 
FROM   T_OBJET 
EXCEPT 
SELECT MAC_NOM 
FROM   T_MACHINE

II-C. Nouveau type XML (norme SQL:2003)



SQL Server accepte dorénavant le type XML comme le prévoit la norme SQL:2003. Ce type SQL permet d'insérer une grappe XML valide ou un document XML validé par rapport à un schéma XSD. De plus des méthodes spécifiques ont été introduites et un document XML validé peut être indexé de manière interne (voir ci-après).

Les types DATE et TIME étaient prévus, mais n'ont finalement pas été intégrés à cette version. Des problèmes de performances dans l'implémentation de ces types seraient à l'origine de la décision de MS de ne pas les intégrer à la version primale de MS SQL Server 2005

II-D. Amélioration des types existants



Les types VARCHAR, NVARCHAR et VARBINARY ont été améliorés et peuvent franchir la barre des 8000 octets. Pour cela, il faut indiquer une taille indéfinie à l'aide du marqueur « max ».


Exemple
Sélectionnez
CREATE TABLE T_MAX 
(MAX_VARCHAR   VARCHAR(max), 
  MAX_NVARCHAR  NVARCHAR(max), 
  MAX_VARBIN    VARBINARY(max)) 

INSERT INTO T_MAX VALUES (REPLICATE('X', 10000), REPLICATE('Y', 100000), 
    CAST(REPLICATE('F', 1000000) AS VARBINARY(max))

Ils restent néanmoins limités à 2 Go de données.

Prenez simplement conscience qu'un LIKE sur une colonne de type VARCHAR(max) contenant en moyenne 60 000 caractères dans une table de plusieurs dizaines de milliers de lignes, risque de prendre… un certain temps !

II-E. Écriture des expressions de table (CTE : Common Table Expression, norme SQL:1999)

Les expressions de tables permettent des écritures très synthétiques de requêtes SQL. Elles ont été introduites avec la norme SQL:1999. Leur intérêt principal est de permettre des expressions de requêtes récursives.

Extrait de mon livre « SQL » Pearson Education 2005, collection Synthex, Co écrit avec Christian Soutou :

"Une expression de table consiste à exprimer une requête SELECT que l'on considérera comme une table dans la requête qui suivra cette expression. La création d'une vue répond à ce même principe tout en étant considérée comme un objet persistant de la base de données tandis que l'expression de table est créée dynamiquement et pour les besoins spécifiques de la requête.
L'expression de table est utile pour simplifier certaines requêtes. Elle s'avère indispensable pour permettre un traitement récursif des données de la requête, parce qu'une corrélation est possible entre l'expression de table et la requête qui la construit."

Exemple : soit le réseau de transport suivant (théorie des graphes) …

Image non disponible

… composé de la table :

 
Sélectionnez
CREATE TABLE T_JOURNEY 
(JNY_FROM_TOWN  VARCHAR(32), 
  JNY_TO_TOWN    VARCHAR(32), 
  JNY_MILES      INTEGER)



… avec les données :

 
Sélectionnez
INSERT INTO T_JOURNEY VALUES ('PARIS',            'NANTES',           385) 
INSERT INTO T_JOURNEY VALUES ('PARIS',            'CLERMONT-FERRAND', 420) 
INSERT INTO T_JOURNEY VALUES ('PARIS',            'LYON',             470) 
INSERT INTO T_JOURNEY VALUES ('CLERMONT-FERRAND', 'MONTPELLIER',      335) 
INSERT INTO T_JOURNEY VALUES ('CLERMONT-FERRAND', 'TOULOUSE',         375) 
INSERT INTO T_JOURNEY VALUES ('LYON',             'MONTPELLIER',      305) 
INSERT INTO T_JOURNEY VALUES ('LYON',             'MARSEILLE',        320) 
INSERT INTO T_JOURNEY VALUES ('MONTPELLIER',      'TOULOUSE',         240) 
INSERT INTO T_JOURNEY VALUES ('MARSEILLE',        'NICE',             205)



Une question que l'on peut se poser est la suivante : quel est le plus court chemin pour aller de Paris à Toulouse ?
Avant l'introduction du CTE et des requêtes récursives, il n'existait pas de solution sous forme d'une requête SQL à cette simple question. Désormais, la requête suivante répond à la question :

 
Sélectionnez
WITH 
   journey (DESTINATION, ETAPES, DISTANCE, CHEMIN) 
   AS 
      (SELECT DISTINCT JNY_FROM_TOWN, 0, 0, CAST('PARIS' AS VARCHAR(MAX)) 
       FROM   T_JOURNEY 
       WHERE  JNY_FROM_TOWN = 'PARIS' 
       UNION  ALL 
       SELECT JNY_TO_TOWN, departure.ETAPES + 1, 
              departure.DISTANCE + arrival.JNY_MILES, 
              departure.CHEMIN + ', ' + arrival.JNY_TO_TOWN 
       FROM   T_JOURNEY AS arrival 
              INNER JOIN journey AS departure 
                    ON departure.DESTINATION = arrival.JNY_FROM_TOWN), 
   short (DISTANCE) 
   AS 
      (SELECT MIN(DISTANCE) 
       FROM   journey 
       WHERE  DESTINATION = 'TOULOUSE') 
SELECT * 
FROM   journey j 
       INNER JOIN short s 
             ON j.DISTANCE = s.DISTANCE 
WHERE  DESTINATION = 'TOULOUSE'
Image non disponible

La clause WITH introduisant le CTE est utilisable aussi dans les ordres DELETE, INSERT, UPDATE et dans la construction des vues. Par exemple on peut supprimer tout un sous arbre partant d'un nœud dans une table présentant une hiérarchie en auto référence.



Vous pouvez lire ici un article très complet sur le sujet. Il doit paraitre en français dans SQL Server magazine d'octobre 2005.

II-F. Amélioration de l'intégrité référentielle (norme SQL:1992)

Deux nouvelles manières de gérer l'intégrité référentielle ont été implémentées. Bien que datant de la norme SQL2 (1992), MS SQL Server était en retard à ce sujet.

II-F-1. IR et SET NULL


Désormais en cas de modification de la valeur de la clef, comme en cas de suppression de la référence, les lignes filles peuvent voir leurs clefs étrangères valuées à NULL.

II-F-2. IR et SET DEFAULT


Désormais en cas de modification de la valeur de la clef, comme en cas de suppression de la référence, les lignes filles peuvent voir leurs clefs étrangères valuées à la valeur par défaut définie dans l'expression de construction de la table.

L'intérêt de ces deux nouvelles règles de gestion de l'intégrité référentielle réside dans l'obtention de performances par déport de l'effort de suppression comme par minimisation du verrouillage. En effet, avec un tel mécanisme, la suppression des lignes filles des tables référencées peut se faire dans un batch de nuit (ramasse-miette), plutôt que par une cascade de « delete » à un moment de la journée ou la charge est maximale.



Exemple
Sélectionnez
CREATE TABLE T_CLIENT_CLI 
(CLI_ID        INTEGER NOT NULL IDENTITY PRIMARY KEY, 
  CLI_NOM       VARCHAR(32)) 

CREATE TABLE T_FACTURE_FAC 
(FAC_ID        INTEGER NOT NULL IDENTITY PRIMARY KEY, 
  FAC_DATE      DATETIME NOT NULL CURRENT_TIMESTAMP, 
  FAC_MONTANT   FLOAT NOT NULL, 
  CLI_ID        INTEGER DEFAULT 0 
               FOREIGN KEY REFERENCES T_CLIENT_CLI (CLI_ID) 
                  ON UPDATE SET DEFAULT 
                  ON DELETE SET NULL)

II-G. Fonctions de classement et d'énumération (norme SQL:2003)



Certaines fonctions de classement et d'énumération, dites de fenêtrage, prévues par la norme SQL:2003 ont été ajoutées à SQL Server 2005 : RANK, DENSE_RANK et ROW_NUMBER. Microsoft a rajouté NTILE qui permet des regroupements par tranches énumérées par des valeurs discrètes.
Extrait de mon livre « SQL » Pearson Education 2005, collection Synthex, Co écrit avec Christian Soutou :
"
Fonctions de fenêtrage et statistiques avancées (SQL:2003)

Les fonctions de « fenêtrage » s'appliquent au résultat de la requête et permettent par exemple la numérotation des lignes retournées ou l'établissement d'un rang. La syntaxe (simplifiée) est la suivante :

 
Sélectionnez
{ RANK() 
   | DENSE_RANK() 
   | PERCENT_RANK() 
   | CUME_DIST() 
   | ROW_NUMBER() } OVER <expression_specification>


RANK permet le classement absolu avec comptage des ex aequo et DENSE_RANK sans le comptage des ex aequo. PERCENT_RANK un classement en pourcentage. CUM_DIST la distribution cumulative et ROW_NUMBER numérote les lignes.
L'expression de spécification doit contenir l'ordre dans lequel les colonnes ou expressions doivent être triées pour que le classement ou la numérotation opère.

Exemple :
Sélectionnez
SELECT   ROW_NUMBER() OVER(ORDER BY USR_ID) RNUM, 
         USR_ID, USR_NOM, USR_PRENOM, 
         RANK() OVER(ORDER BY USR_PRENOM) RANK, 
         DENSE_RANK() OVER(ORDER BY USR_PRENOM) DENSE_RNK 
FROM     T_UTILISATEUR_USR
Image non disponible

-

Microsoft SQL Server 2005 n'implémente pas les fonctions normatives PERCENT_RANK et CUM_DIST.



Quant à la fonction NTILE, spécifique à SQL Server 2005, elle permet de regrouper par tranches contenant un nombre en principes égaux de lignes les valeurs des colonnes visées. Cela peut être utile pour classer par sous-groupes les éléments d'un ensemble. Par exemple, dans une classe de 16 élèves on peut créer trois groupes de travail pour les cours de gymnastique. Les forts, les moins forts et les faibles. Dans ce cas la fonction NTILE placera les six premiers des épreuves de sélection sportive dans le groupe 1, puis six en suivant dans le groupe 2 et enfin, 4 dans le groupe 3. L'expression d'une telle requête pourrait prendre la forme :

 
Sélectionnez
SELECT ELV_NOM, 
                NTILE(3) OVER(ORDER BY ELV_NOTE_GYM) AS ELV_GROUPE, 
                ELV_NOTE_GYM 
FROM   T_ELEVE_ELV
Image non disponible

ces fonctions de classement sont des fonctions dites de « fenêtrage ». Elles ne s'appliquent qu'aux lignes devant être affichées et ne peuvent ni figurer dans une sous requête classique, ni dans une clause WHERE, HAVING, etc. parce qu'elles s'appliquent après que les lignes du résultat aient été construites. Ainsi il n'est pas possible d'utiliser la fonction ROW_NUMBER ou NTILE pour faire directement de la pagination. En revanche, une telle requête peut être encapsulée en tant que sous-requête, table dans la clause FROM et servir à différents usages.



Voici un exemple, de pagination dans un jeu de résultats avec deux méthodes différentes.

1) Pagination par bloc de lignes contrôlée (les lignes retournées sont contrôlées dans le filtre WHERE) :

 
Sélectionnez
SELECT * 
FROM   (SELECT   ROW_NUMBER() OVER(ORDER BY USR_ID) RNUM, 
                 USR_ID, USR_NOM, USR_PRENOM, 
        FROM     T_UTILISATEUR_USR) T 
WHERE  RNUM BETWEEN 10 AND 19


Ici on retourne les lignes numérotées 10 à 19.

2) Pagination par nombre de pages (le nombre de pages est fixé, le nombre de lignes inconnu, la page retournée est contrôlée dans le filtre WHERE) :

 
Sélectionnez
SELECT * 
FROM   (SELECT   NTILE(25) OVER(ORDER BY USR_ID) NTL, 
                 USR_ID, USR_NOM, USR_PRENOM, 
        FROM     T_UTILISATEUR_USR) T 
WHERE  NTL = 7


Ici on fixe le nombre de pages à 25 et l'on retourne la page 7

Una autre construction plus élégante est possible via la CTE.

II-H. Opérateur PIVOT / UNPIVOT


L'horrible, mais traditionnel opérateur PIVOT, bien qu'absent de la norme SQL fait son apparition dans SQL Server 2005 afin de permettre de réaliser des tableaux croisés. Il s'agit simplement d'une astuce cosmétique pour présenter des données avec de nouvelles colonnes dont les noms sont extraits d'une des colonnes de la requête.

Exemple :
Sélectionnez
CREATE TABLE T_VENTE_VTE 
(VTE_ID        INT, 
  VTE_PERIODE   VARCHAR(8), 
  VTE_ZONE      VARCHAR(6), 
  VTE_CA        FLOAT) 

INSERT INTO T_VENTE_VTE VALUES (1, 'TR 1', 'Sud', 232534.34) 
INSERT INTO T_VENTE_VTE VALUES (2, 'TR 2', 'Sud', 565537.65) 
INSERT INTO T_VENTE_VTE VALUES (4, 'TR 3', 'Sud', 254537.89) 
INSERT INTO T_VENTE_VTE VALUES (5, 'TR 4', 'Sud', 345564.98) 
INSERT INTO T_VENTE_VTE VALUES (6, 'TR 1', 'Nord', 234507.67) 
INSERT INTO T_VENTE_VTE VALUES (7, 'TR 3', 'Nord', 787537.88) 
INSERT INTO T_VENTE_VTE VALUES (8, 'TR 4', 'Nord', 675455.62) 

-- Avant SQL Server 2005 : 
SELECT VTE_ZONE, SUM(VTE_CA) AS TRIMESTRE_1, 
       (SELECT SUM(VTE_CA) 
        FROM   T_VENTE_VTE 
        WHERE  VTE_PERIODE = 'TR 2' 
          AND  VTE_ZONE = VTE.VTE_ZONE) AS TRIMESTRE_2, 
       (SELECT SUM(VTE_CA) 
        FROM   T_VENTE_VTE 
        WHERE  VTE_PERIODE = 'TR 3' 
          AND  VTE_ZONE = VTE.VTE_ZONE) AS TRIMESTRE_3, 
       (SELECT SUM(VTE_CA) 
        FROM   T_VENTE_VTE 
        WHERE  VTE_PERIODE = 'TR 4' 
          AND  VTE_ZONE = VTE.VTE_ZONE) AS TRIMESTRE_3 
FROM   T_VENTE_VTE VTE 
WHERE  VTE_PERIODE = 'TR 1' 
GROUP  BY VTE_ZONE 

-- Avec SQL Server 2005 : 
SELECT VTE_ZONE, SUM([TR 1]) AS TRIMESTRE_1, SUM([TR 2]) AS TRIMESTRE_2, 
    SUM([TR 3]) AS TRIMESTRE_3, SUM([TR 4]) AS TRIMESTRE_4 
FROM  T_VENTE_VTE 
PIVOT (SUM(VTE_CA) FOR VTE_PERIODE IN ([TR 1], [TR 2], [TR 3], [TR 4])) 
    AS TRIMESTRE 
GROUP BY VTE_ZONE
Image non disponible
 
Sélectionnez
-- les mêmes résultats sans le cosmétique du tableau croisé : 
SELECT VTE_ZONE, VTE_PERIODE, SUM(VTE_CA) AS CA 
FROM   T_VENTE_VTE VTE 
GROUP  BY VTE_ZONE, VTE_PERIODE

Si cette technique permet de réconcilier les aficionados d'Access et des tableaux croisés avec SQL Server, tant mieux. Mais ce « truc » possède de très nombreux inconvénients majeurs :



1) Aucune conformité aux normes SQL et franchement pas standard : la transformation de valeurs en nom de colonnes est une absurdité et le recours aux crochets pour nommer les colonnes provenant des valeurs n'obéit à aucune logique, ni aucun standard si ce n'est les spécificités de MS SQL Server.

2) Même si le plan de requête parait plus simple, il n'est pas certain que l'effort en termes d'E/S soit moindre. En effet l'utilisation d'un tel opérateur empêche en principe l'utilisation des index.
3) Toute opération cosmétique grève énormément les performances d'un serveur SQL parce qu'il n'a pas été prévu pour cela, alors qu'un outil de présentation spécialement conçu à cet effet pourra donner le même rendu en minimisant les ressources.

4) La clause IN de l'opérateur PIVOT n'a pas été rendue générique. En l'occurrence l'écriture très tentante d'une requête du genre :

 
Sélectionnez
PIVOT (SUM(VTE_CA) FOR VTE_PERIODE IN (VTE_PERIODE) AS TRIMESTRE


ou encore :

 
Sélectionnez
PIVOT (SUM(VTE_CA) FOR VTE_PERIODE 
    IN (SELECT DISTINCT VTE_PERIODE FROM T_VENTE_VTE) AS TRIMESTRE


n'est pas possible. Il faut spécifier « en dur » et connaître d'avance les colonnes !

En conclusion : les opérateurs PIVOT / UNPIVOT revêtent peu d'intérêt et sont à éviter systématiquement pour qui veut des performances.

UNPIVOT est l'opération inverse de PIVOT, mais ne peut reproduire exactement les données initiales du fait du traitement spécifique des absences de valeurs (marqueurs NULL).

Pour compléter votre information, l'article de Reanaud Harduin sur le sujet.

II-I. Opérateur APPLY


L'opérateur APPLY a pour but d'appliquer une jointure à un ensemble de lignes extraites d'une colonne d'une table et sa table hôte. Mais, me direz-vous, est-il possible de mettre des lignes dans une colonne de table ? Oui, si l'on considère qu'une fonction table peut être appliquée pour une colonne, ou qu'une colonne peut contenir du xml dont l'extraction d'un nœud peut retourner un ensemble de lignes…

Voici un exemple, complet…
La fonction table suivante retourne une table constituée des 7 jours de la semaine contenant la valeur du paramètre DATETIME qu'on lui passe :

 
Sélectionnez
CREATE FUNCTION F_WEEKDAYTABLE (@A_DATE DATETIME) 
RETURNS @WEEKDAYTABLE TABLE ("DATE" DATETIME primary key, 
                             JOUR   VARCHAR(8)) 
BEGIN 
-- obtention de la date avec heure 0 
   SET @A_DATE = CAST(FLOOR(CAST(@A_DATE AS FLOAT)) AS DATETIME); 
-- recherche du lundi 
   WHILE DATEPART(WEEKDAY, @A_DATE) <> 1 
         SET @A_DATE = @A_DATE -1 
-- insertion des jours de la semaine dans la table 
   INSERT INTO @WEEKDAYTABLE VALUES (@A_DATE,     'Lundi') 
   INSERT INTO @WEEKDAYTABLE VALUES (@A_DATE + 1, 'Mardi') 
   INSERT INTO @WEEKDAYTABLE VALUES (@A_DATE + 2, 'Mercredi') 
   INSERT INTO @WEEKDAYTABLE VALUES (@A_DATE + 3, 'Jeudi') 
   INSERT INTO @WEEKDAYTABLE VALUES (@A_DATE + 4, 'Vendredi') 
   INSERT INTO @WEEKDAYTABLE VALUES (@A_DATE + 5, 'Samedi') 
   INSERT INTO @WEEKDAYTABLE VALUES (@A_DATE + 6, 'Dimanche') 
-- retour   
   RETURN 
END 

-- la table suivante contient des factures : 
CREATE TABLE T_FACTURE_FCT 
(FCT_ID       INTEGER NOT NULL PRIMARY KEY, 
  FCT_DATE     DATETIME NOT NULL, 
  CLI_ID       INTEGER NOT NULL) 

INSERT INTO T_FACTURE_FCT VALUES (145, '20050718', 33) 
INSERT INTO T_FACTURE_FCT VALUES (178, '20050720', 21) 
INSERT INTO T_FACTURE_FCT VALUES (213, '20050722', 47)
Image non disponible

Les factures doivent être envoyées le jeudi qui suit la date de la facture. Comment exprimer cela à l'aide des éléments ci-dessous et obtenir :

Image non disponible
Une première tentative :
Sélectionnez
SELECT * 
FROM   T_FACTURE_FCT F 
       CROSS JOIN dbo.F_WEEKDAYTABLE (F.FCT_DATE) W 
WHERE  W.JOUR = 'Jeudi'



Se solde par une erreur à la compilation :

Serveur : Msg 170, Niveau 15, État 1, Ligne 3
Ligne 3 : syntaxe incorrecte vers '.'.

En effet on ne peut pas exprimer une colonne d'une table de la clause FROM en paramètre dans une fonction contenue dans cette même clause FROM. Ce qui était impossible sous SQL Server 2000 devient possible en version 2005 : la solution passe par l'un des deux nouveaux opérateurs de jointure CROSS APPLY ou OUTER APPLY…

 
Sélectionnez
SELECT FCT_ID, FCT_DATE, CLI_ID, 
       CASE 
          WHEN FCT_DATE > W.DATE THEN WW.DATE 
          ELSE W.DATE 
       END AS DATE_ENVOI 
FROM   T_FACTURE_FCT F 
       CROSS APPLY dbo.F_WEEKDAYTABLE (F.FCT_DATE) W 
       CROSS APPLY dbo.F_WEEKDAYTABLE (F.FCT_DATE + 7) WW 
WHERE  W.JOUR = 'Jeudi' 
  AND  WW.JOUR = 'Jeudi'
Image non disponible

MS SQL Server dispose donc de deux opérateurs APPLY : CROSS APPLY pour un produit cartésien et OUTER APPLY pour une jointure externe.

II-J. Clause OUTPUT



Voici une clause intéressante pour les ordres SQL de mise à jour. Elle permet de tout connaître de ce qui s'est passé dans un tel ordre (INSERT, UPDATE, DELETE). Son principe consiste à répercuter les informations d'ajouts, modifications ou suppressions dans une table de votre choix. Voici un exemple d'utilisation d'une telle clause.

 
Sélectionnez
-- création d'une table de trace pour pister les modifications 
CREATE TABLE T_TRACE_TRC 
(TRC_ID INTEGER      IDENTITY NOT NULL PRIMARY KEY, 
  TRC_DATEHEURE       DATETIME DEFAULT CURRENT_TIMESTAMP, 
  TRC_TABLE           NVARCHAR(128), 
  TRC_CLEF            INTEGER, 
  TRC_DATA            NVARCHAR(256), 
  TRC_HOST_NAME       NVARCHAR(128), 
  TRC_PROGRAM_NAME    NVARCHAR(128), 
  TRC_NT_USER_NAME    NVARCHAR(128), 
  TRC_NET_ADDRESS     NCHAR(12), 
  TRC_LOGIN_NAME      NVARCHAR(128)) 

-- ordre DELETE avec clause OUTPUT : 
DELETE FROM T_CHAMBRE_CHB 
OUTPUT CURRENT_TIMESTAMP, 
       'T_CHAMBRE_CHB', 
       deleted.CHB_ID, 
       'CHB_NUM = ' + CAST(deleted.CHB_NUM AS VARCHAR(16)) + 
       ', CHB_COUCHAGE = '+CAST(deleted.CHB_COUCHAGE AS VARCHAR(16)), 
       p.host_name, 
       p.program_name, 
       p.nt_user_name, 
       p.net_address, 
       p.login_name 
       INTO T_TRACE_TRC 
FROM   T_CHAMBRE_CHB CHB 
       CROSS JOIN master.dbo.sysprocesses p 
WHERE  CHB.CHB_COUCHAGE >= 5 
  AND  p.spid = @@spid



Dans cet exemple nous faisons une jointure croisée avec la table des processus pour le processus en cours afin de rapatrier les informations de l'utilisateur, du programme et du nœud réseau sur lequel il travaille afin d'alimenter la table de trace avec ces informations, comme avec les informations concernant les éléments supprimés. Notez la présence de la pseudo table deleted qui contient les lignes en cours de suppression, comme dans le cadre d'un trigger. De même la table inserted est disponible dans la clause OUTPUT.

Dans sa première version, la clause OUTPUT ne pouvait alimenter qu'une variable de type table devant être préalablement déclarée. Il a été annoncé que cette clause OUTPUT pourrait alimenter une table persistante quelconque. C'est ce que nous avons fait dans notre exemple. Néanmoins nous n'avons pas constaté dans le bêta 3 cette évolution.

II-K. Amélioration et extension de la clause TOP


Une des critiques souvent faites sur cette clause qui permet de limiter le nombre de lignes retournées est qu'elle n'était pas paramétrable. C'est désormais chose faite. On peut mettre dans TOP une variable comme une sous-requête. Voici un exemple qui permet de retourner la moitié des lignes d'une table :

 
Sélectionnez
SELECT TOP(SELECT COUNT(*) / 2 
           FROM T_CHAMBRE) 
       * 
FROM   T_CHAMBRE



Il est maintenant possible d'utiliser la clause TOP dans les autres ordres SQL du DDL : INSERT, UPDATE, DELETE. Cela peut être très intéressant pour découper en plusieurs lots une requête qui écrit des données et donc minimiser le volume des transactions.

Exemple :
Sélectionnez
WHILE EXISTS (SELECT * 
              FROM   T_CLIENT 
              WHERE  CLI_NOM <> UPPER(CLI_NOM)) 
   UPDATE T_CLIENT 
   TOP    400 
   SET    CLI_NOM = UPPER(CLI_NOM)


Dans cette requête, on met en majuscules le nom des clients par paquet de 400 tant qu'il existe des noms de client qui ne l'ont pas encore été.

Autrefois, il fallait recourir pour ce faire à l'indicateur ROWCOUNT. Microsoft annonce que celle-ci ne sera plus supportée dans les versions futures de SQL Server.

II-L. Échantillon de table (TABLE SAMPLE)


Cette nouvelle clause permet de retourner un échantillon de lignes de la table plutôt que de retourner toutes les lignes. Cette clause complète un peu la clause TOP, avec un avantage, les lignes sont retournées dans des pages de la table prises au hasard, alors que TOP implique un classement ce qui implique donc échantillon organisé donc peu représentatif.
Il est même prévu que la méthode d'échantillonnement puisse être choisie, voire d'implémenter sa propre méthode.

La syntaxe est la suivante :
Sélectionnez
TABLESAMPLE [SYSTEM] (nombre [ PERCENT | ROWS ] ) [ REPEATABLE (graine) ] 
Exemple : 
SELECT * 
FROM   T_FACTURE TABLESAMPLE (2 PERCENT)


Dans le cas où l'on désire obtenir toujours le même jeu de lignes dans l'échantillon, on peut proposer une valeur numérique arbitraire pour la valeur graine. Dès lors, avec l'utilisation de cette même valeur, l'échantillon de pages retournées sera le même à chaque exécution, à condition que les pages n'aient pas été réorganisées (DBCC INDEXDEFRAG par exemple).

Exemple :
Sélectionnez
SELECT * 
FROM   T_FACTURE TABLESAMPLE (2 PERCENT) REPEATABLE 12345

Comme TABLESAMPLE fonctionne sur des pages et non des lignes, le nombre de lignes est approximatif et dépend du nombre de lignes par page. Ceci peut être pénalisant dans de petites tables ou TABLESAMPLE peut ne rien renvoyer dans le cas d'un 40 % par exemple si la totalité des lignes est contenue dans une page. Conséquence : TABLESAMPLE n'a d'intérêt que pour des tables volumineuses (plusieurs centaines de pages…).

II-M. Schéma SQL (norme SQL:1992)


La notion de schéma SQL a été améliorée (elle se trouve maintenant proche de la norme SQL2) et il est désormais possible de créer dans une même base différents schémas sans passer obligatoirement par un nouvel utilisateur. Cela revient à dire qu'un objet n'appartient plus directement à un utilisateur, mais à un schéma. En outre différents utilisateurs peuvent ajouter, modifier ou retirer des objets du schéma pourvu qu'ils en aient acquis les privilèges.

II-N. Sécurité


La sécurité a été grandement améliorée : des pseudo ordre SQL sont disponibles là ou des procédures complexes et absconses devaient être employées. Ainsi on trouve les ordres Transact SQL :

 
Sélectionnez
CREATE USER ... WITH DEFAULT_SCHEMA ... 
CREATE LOGIN ... 
GRANT ... ON SCHEMA ... TO ...


Comme nous l'avons déjà dit, la notion d'utilisateur SQL devient indépendante du schéma.
Un accès au serveur peut être formé avec un certificat (CERTIFICATE ou CREDENTIAL) ou une clef de chiffrement asymétrique. Cette technique est notamment requise pour authentifier certains processus notamment dans le cadre de l'utilisation des web services intégrés à MS SQL Server et par conséquent faire dialoguer des Serveurs SQL à travers le web.
Enfin, il est possible de caler la politique de gestion des mots de passe (« password policies ») sur celle de Windows Server.,

Notons que la gestion des privilèges (GRANT, REVOKE) a été entièrement revue afin de gérer tous les nouveaux objets de SQL Server 2005. Ce qui existait sous SQL Server 2000 reste, bien entendu compatible. Les privilèges sont imbriqués de manière hiérarchique.

II-O. Vues système


Microsoft utilise les nouvelles possibilités de schéma au sein des bases de données de SQL Server 2005 en ajoutant systématiquement à toute base de données créée un schéma de nom « sys » regroupant les vues système interne à SQL Server.

Par exemple, la vue sys.database_files remplace avantageusement la table sysfiles :

  • elle contient plus d'informations que sysfiles ;
  • les informations contenues sont plus claires ;
  • les vues sont plus faciles à sécuriser.

Si vous devez recourir aux informations système, préférez dans l'ordre :

  1. les vues normatives (SQL2) d'information de schéma (INFORMATION_SCHEMA.TABLE par exemple)
  2. les vues système (sys.objects par exemple)
  3. les procédures spécialisées (sp_help par exemple)et en dernier recours
  4. les tables système (sysobjects par exemple)

En effet, seules les vues et les procédures sont compatibles d'une version à l'autre et les vues normatives sont à préférer pour des raisons de compatibilité.

II-P. Conclusion


Même s'il reste des efforts à faire du côté de SQL, tel que l'implémentation des types DATE et TIME (possible avec CLR), du type ROW ou ARRAY (ces derniers étant simulable par du xml) et qu'il manque encore certaines constructions SQL telles que le Row Value Constructor, le concept d'assertion ou encore les prédicats UNIQUE, DISTINCT ou MATCH, force est de constater que le SQL de MS SQL Server 2005 est d'un niveau élevé et largement suffisant pour la très grande majorité des développements.


précédentsommairesuivant

Copyright © 2005 SQLPro. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.