web-dev-qa-db-fra.com

Erreur SQL avec Order By dans une sous-requête

Je travaille avec SQL Server 2005. 

Ma requête est:

SELECT (
  SELECT COUNT(1) FROM Seanslar WHERE MONTH(tarihi) = 4
  GROUP BY refKlinik_id
  ORDER BY refKlinik_id
) as dorduncuay

Et l'erreur:

La clause ORDER BY n'est pas valide dans les vues, fonctions en ligne, dérivées tables, sous-requêtes et expressions de table communes, sauf TOP ou FOR XML est également spécifié.

Comment utiliser ORDER BY dans une sous-requête?

59
cagin

C'est l'erreur que vous obtenez (c'est moi qui souligne):

La clause ORDER BY n'est pas valide dans vues, fonctions en ligne, dérivées tables, sous-requêtes et table commune expressions, sauf si TOP ou FOR XML est également spécifié.

Alors, comment pouvez-vous éviter l'erreur? En spécifiant TOP, serait une possibilité, je suppose.

SELECT (
  SELECT TOP 100 PERCENT
  COUNT(1) FROM Seanslar WHERE MONTH(tarihi) = 4
  GROUP BY refKlinik_id
  ORDER BY refKlinik_id
) as dorduncuay
90
Tomalak

Outre le fait que order by ne semble pas avoir de sens dans votre requête .... Pour utiliser order by dans une sous-sélection, vous devez utiliser TOP 2147483647.

SELECT (
  SELECT TOP 2147483647
  COUNT(1) FROM Seanslar WHERE MONTH(tarihi) = 4
  GROUP BY refKlinik_id
  ORDER BY refKlinik_id
) as dorduncuay

Si j'ai bien compris, "TOP 100 PERCENT" ne garantit plus la commande à partir de SQL 2005:

Dans SQL Server 2005, la commande ORDER BY La clause est utilisée dans une définition de vue uniquement pour déterminer les lignes qui sont retourné par la clause TOP. L'ordre La clause BY ne garantit pas la commande résulte lorsque la vue est interrogée, sauf si ORDER BY est également spécifié dans la requête elle-même.

Voir Modifications récentes de SQL Server 2005

J'espère que ça aide, Patrick

32
Patrick Wolf

Si vous travaillez avec SQL Server 2012 ou version ultérieure, il est désormais facile de résoudre ce problème. Ajouter un offset 0 rows:

SELECT (
  SELECT
  COUNT(1) FROM Seanslar WHERE MONTH(tarihi) = 4
  GROUP BY refKlinik_id
  ORDER BY refKlinik_id OFFSET 0 ROWS
) as dorduncuay
14
Jez

Vous n'avez pas besoin de order by dans votre requête secondaire. Déplacez-le dans la requête principale et incluez la colonne que vous souhaitez classer dans la sous-requête.

cependant, votre requête ne fait que renvoyer un compte, je ne vois donc pas le point de la commande par.

4
cjk

Ajoutez la commande Top à votre sous-requête ...

SELECT 
(
SELECT TOP 100 PERCENT 
    COUNT(1) 
FROM 
    Seanslar 
WHERE 
    MONTH(tarihi) = 4
GROUP BY 
    refKlinik_id
ORDER BY 
    refKlinik_id
) as dorduncuay

:)

3
user110714

Dans cet exemple, la commande n'ajoute aucune information - le COUNT d'un ensemble est le même quel que soit son ordre!

Si vous sélectionniez quelque chose qui dépendait de l'ordre, vous auriez besoin de faire l'une des choses que le message d'erreur vous indique - utilisez TOP ou FOR XML.

2
AakashM

Une sous-requête (vue imbriquée) telle que vous l'avez renvoyée renvoie un ensemble de données que vous pouvez ensuite classer dans votre requête appelante. La commande de la sous-requête elle-même n'aura aucune incidence (fiable) sur l'ordre des résultats dans votre requête.

En ce qui concerne votre code SQL lui-même: A) Je n’ai vu aucune raison de passer commande car vous ne renvoyiez qu’une seule valeur . B) Je ne voyais aucune raison pour la sous-requête, car vous ne renvoyiez qu’une seule valeur.

J'imagine qu'il y a beaucoup plus d'informations ici que vous voudrez peut-être nous dire afin de résoudre le problème que vous avez.

2
Robin Day

peut-être que cette astuce aidera quelqu'un

SELECT
    [id],
    [code],
    [created_at]                          
FROM
    ( SELECT
        [id],
        [code],
        [created_at],
        (ROW_NUMBER() OVER (
    ORDER BY
        created_at DESC)) AS Row                                 
    FROM
        [Code_tbl]                                 
    WHERE
        [created_at] BETWEEN '2009-11-17 00:00:01' AND '2010-11-17 23:59:59'                                  
        )  Rows                          
WHERE
    Row BETWEEN 10 AND    20;

ici la sous-requête interne ordonnée par le champ created_at (peut être n'importe laquelle de votre table)

2
Vlad

Pour moi, cette solution fonctionne bien aussi:

SELECT tbl.a, tbl.b
FROM (SELECT TOP (select count(1) FROM yourtable) a,b FROM yourtable order by a) tbl
1
Qohelet

Si vous construisez une table temporaire, déplacez la clause ORDER BY de l'intérieur du bloc de code de la table temporaire vers l'extérieur.

Interdit:

SELECT * FROM (
SELECT A FROM Y
ORDER BY Y.A
) X;

Permis:

SELECT * FROM (
SELECT A FROM Y
) X
ORDER BY X.A;
1
MacGyver

Essayez de déplacer la clause order by en dehors de la sous-sélection et d'ajouter le champ order by dans la sous-sélection.



SELECT * FROM 

(SELECT COUNT(1) ,refKlinik_id FROM Seanslar WHERE MONTH(tarihi) = 4 GROUP BY refKlinik_id)
as dorduncuay 

ORDER BY refKlinik_id 

1
indrap

Bonne journée

pour certains gars, l'ordre dans la sous-requête est discutable. la commande par en sous-requête est indispensable si vous devez supprimer des enregistrements en fonction d'un tri . like 

delete from someTable Where ID in (select top(1) from sometable where condition order by insertionstamp desc)

afin que vous puissiez supprimer la dernière table de formulaire d'insertion . il y a trois façons d'effectuer cette suppression.

cependant, la commande by dans la sous-requête peut être utilisée dans de nombreux cas.

pour les méthodes de suppression qui utilisent order by dans la revue de sous-requête ci-dessous link

http://web.archive.org/web/20100212155407/http://blogs.msdn.com/sqlcat/archive/2009/05/21/fast-ordered-delete.aspx

j'espère que ça aide. Merci à tous

1
Omar Kamel

Sur les besoins possibles pour commander une sous-requête est lorsque vous avez une union:

Vous générez un carnet d’appel de tous les enseignants et étudiants.

SELECT name, phone FROM teachers
UNION
SELECT name, phone FROM students

Vous souhaitez l'afficher d'abord avec tous les enseignants, suivi de tous les élèves, tous deux ordonnés par. Donc, vous ne pouvez pas appliquer un ordre global par.

Une solution consiste à inclure une clé pour forcer un premier ordre, puis à ordonner les noms:

SELECT name, phone, 1 AS orderkey FROM teachers
UNION
SELECT name, phone, 2 AS orderkey FROM students
ORDER BY orderkey, name

Je pense que son chemin est plus clair qu'un faux résultat de sous-requête compensatoire.

0
iguypouf

J'utilise ce code pour obtenir le deuxième salaire le plus bas

Je suis aussi obtenir une erreur comme

La clause ORDER BY n'est pas valide dans les vues, les fonctions en ligne, les tables dérivées, les sous-requêtes et les expressions de table communes, sauf si TOP ou FOR XML est également spécifié.

TOP 100 j'ai utilisé pour éviter l'erreur

sélectionnez * parmi ( sélectionnez tableau.Coloumn1, CONVERT (varchar, ROW_NUMBER () OVER (ORDER BY (SELECT 1))) AS Rowno à partir de ( sélectionnez top 100 * dans Tableau1 order. par Coloumn1 desc) comme tbl) comme tbl où tbl.Rowno = 2

0
soundar rajan

Pour un décompte simple comme le montre le PO, l'Ordre de n'est pas strictement nécessaire. S'ils utilisent le résultat de la sous-requête, c'est peut-être le cas. Je travaille sur un problème similaire et j'ai la même erreur dans la requête suivante:

- Je veux les lignes de la table des coûts avec une date de mise à jour égale à la date de mise à jour maximale:

    SELECT * FROM #Costs Cost
    INNER JOIN
    (
        SELECT Entityname, costtype, MAX(updatedtime) MaxUpdatedTime
        FROM #HoldCosts cost
        GROUP BY Entityname, costtype
        ORDER BY Entityname, costtype  -- *** This causes an error***
    ) CostsMax
        ON  Costs.Entityname = CostsMax.entityname
        AND Costs.Costtype = CostsMax.Costtype
        AND Costs.UpdatedTime = CostsMax.MaxUpdatedtime
    ORDER BY Costs.Entityname, Costs.costtype

- *** Pour ce faire, il existe quelques options:

- Ajouter une clause TOP superflue, cela ressemble à un bidouillage:

    SELECT * FROM #Costs Cost
    INNER JOIN
    (
        SELECT TOP 99.999999 PERCENT Entityname, costtype, MAX(updatedtime) MaxUpdatedTime
        FROM #HoldCosts cost
        GROUP BY Entityname, costtype
        ORDER BY Entityname, costtype  
    ) CostsMax
        ON Costs.Entityname = CostsMax.entityname
        AND Costs.Costtype = CostsMax.Costtype
        AND Costs.UpdatedTime = CostsMax.MaxUpdatedtime
    ORDER BY Costs.Entityname, Costs.costtype

- **** Créer une table temporaire pour commander le maxCost

    SELECT Entityname, costtype, MAX(updatedtime) MaxUpdatedTime
    INTO #MaxCost
    FROM #HoldCosts cost
    GROUP BY Entityname, costtype
    ORDER BY Entityname, costtype  

    SELECT * FROM #Costs Cost
    INNER JOIN #MaxCost CostsMax
        ON Costs.Entityname = CostsMax.entityname
        AND Costs.Costtype = CostsMax.Costtype
        AND Costs.UpdatedTime = CostsMax.MaxUpdatedtime
    ORDER BY Costs.Entityname, costs.costtype

D'autres solutions de contournement possibles pourraient être les variables CTE ou de table. Mais chaque situation nécessite que vous déterminiez ce qui vous convient le mieux. J'ai tendance à regarder d'abord vers une table temporaire. Pour moi, c'est clair et simple. YMMV.

0
iLWR