web-dev-qa-db-fra.com

Calcul de SQL Server ROW_NUMBER () OVER () pour une table dérivée

Dans certaines autres bases de données (par exemple DB2 ou Oracle avec ROWNUM), je peux omettre la clause ORDER BY Dans la clause OVER() d'une fonction de classement. Par exemple:

ROW_NUMBER() OVER()

Ceci est particulièrement utile lorsqu'il est utilisé avec des tables dérivées ordonnées, telles que:

SELECT t.*, ROW_NUMBER() OVER()
FROM (
    SELECT ...
    ORDER BY
) t

Comment cela peut-il être émulé dans SQL Server? J'ai trouvé des gens utilisant thistrick , mais c'est faux, car il se comportera de manière non déterministe par rapport à l'ordre de la table dérivée:

-- This order here ---------------------vvvvvvvv
SELECT t.*, ROW_NUMBER() OVER(ORDER BY (SELECT 1))
FROM (
    SELECT TOP 100 PERCENT ...
    -- vvvvv ----redefines this order here
    ORDER BY
) t

Un exemple concret (comme on peut le voir sur SQLFiddle ):

SELECT v, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM (
  SELECT TOP 100 PERCENT 1 UNION ALL
  SELECT TOP 100 PERCENT 2 UNION ALL
  SELECT TOP 100 PERCENT 3 UNION ALL
  SELECT TOP 100 PERCENT 4
  -- This descending order is not maintained in the outer query
  ORDER BY 1 DESC
) t(v)

De plus, je ne peux réutiliser aucune expression de la table dérivée pour reproduire la clause ORDER BY Dans mon cas, car la table dérivée peut ne pas être disponible car elle peut être fournie par une logique externe.

Alors comment faire? Puis-je le faire du tout?

12
Lukas Eder

L'astuce Row_Number() OVER (ORDER BY (SELECT 1)) doit [~ # ~] et non [~ # ~] être considérée comme un moyen d'éviter de changer l'ordre des données sous-jacentes. Ce n'est qu'un moyen d'éviter que le serveur effectue un tri supplémentaire et inutile (il peut toujours effectuer le tri mais cela coûtera le minimum possible par rapport au tri par colonne).

Toutes les requêtes dans le serveur SQL ABSOLUMENT DOIT ont une clause ORDER BY Dans la requête la plus à l'extérieur pour que les résultats soient classés de manière fiable et garantie.

Le concept de "maintien de l'ordre d'origine" n'existe pas dans les bases de données relationnelles. Les tables et les requêtes doivent toujours être considérées comme non ordonnées jusqu'à ce qu'une clause ORDER BY Soit spécifiée dans la requête externe.

Vous pouvez essayer la même requête non ordonnée 100 000 fois et toujours la recevoir avec la même commande, et ainsi croire que vous pouvez compter sur cette commande. Mais ce serait une erreur, car un jour, quelque chose va changer et il n'aura pas l'ordre que vous attendez. Un exemple est lorsqu'une base de données est mise à niveau vers une nouvelle version de SQL Server - cela a provoqué de nombreuses requêtes pour modifier son ordre. Mais cela ne doit pas être un changement si important. Quelque chose d'aussi petit que l'ajout ou la suppression d'un index peut entraîner des différences. Et bien plus: Installer un Service Pack. Partitionner une table. Création d'une vue indexée qui inclut la table en question. Atteindre un point de basculement où un scan est choisi au lieu d'une recherche. Etc.

Ne comptez pas sur les résultats à commander, sauf si vous avez dit "Serveur, ORDER BY".

10
ErikE