web-dev-qa-db-fra.com

Les éléments ORDER BY doivent apparaître dans la liste de sélection si SELECT DISTINCT est spécifié

J'ai ajouté les colonnes de la liste de sélection à la liste commande par ordre, mais il me donne toujours l'erreur suivante:

Les éléments ORDER BY doivent apparaître dans la liste de sélection si SELECT DISTINCT est spécifié.

Voici le proc stocké:

CREATE PROCEDURE [dbo].[GetRadioServiceCodesINGroup] 
@RadioServiceGroup nvarchar(1000) = NULL
AS
BEGIN
SET NOCOUNT ON;

SELECT DISTINCT rsc.RadioServiceCodeId,
                rsc.RadioServiceCode + ' - ' + rsc.RadioService as RadioService
FROM sbi_l_radioservicecodes rsc
INNER JOIN sbi_l_radioservicecodegroups rscg 
ON rsc.radioservicecodeid = rscg.radioservicecodeid
WHERE rscg.radioservicegroupid IN 
(select val from dbo.fnParseArray(@RadioServiceGroup,','))
OR @RadioServiceGroup IS NULL  
ORDER BY rsc.RadioServiceCode,rsc.RadioServiceCodeId,rsc.RadioService

END
62
Xaisoft

Essaye ça:

ORDER BY 1, 2

OR

ORDER BY rsc.RadioServiceCodeId, rsc.RadioServiceCode + ' - ' + rsc.RadioService
57
Chris Van Opstal

Bien que ce ne soit pas la même chose, dans un sens, DISTINCT implique un GROUP BY, car chaque DISTINCT peut être ré-écrit en utilisant GROUP BY au lieu. Dans cet esprit, il n’a pas de sens de commander par quelque chose qui ne fait pas partie du groupe global.

Par exemple, si vous avez une table comme celle-ci:

 col1 col2 
 ---- ---- 
 1 1 
 1 2 
 2 1 
 2 2 
 2 3 
 3 1 

et essayez ensuite de l'interroger comme ceci:

SELECT DISTINCT col1 FROM [table] WHERE col2 > 2 ORDER BY col1, col2

Cela n’aurait aucun sens car là pourrait finir par être multiple col2 valeurs par ligne. Lequel devrait-il utiliser pour la commande? Bien sûr, dans cette requête, vous savez que les résultats ne seraient pas tels, mais le serveur de base de données ne peut pas le savoir à l'avance.

Maintenant, votre cas est un peu différent. Vous avez inclus toutes les colonnes du order by _ dans la clause select, et il semblerait donc à première vue qu’ils étaient tous regroupés. Cependant, certaines de ces colonnes ont été incluses dans un champ calculé. Lorsque vous faites cela en combinaison avec distinct, la directive distinct peut niquement être appliquée à résultats finaux du calcul: elle ne sait rien la source du calcul plus.

Cela signifie que le serveur ne sait pas vraiment qu'il peut compter sur ces colonnes. Il sait qu'ils ont été utilisés, mais il ne sait pas si l'opération de calcul peut provoquer un effet similaire à mon premier exemple simple ci-dessus.

Vous devez donc faire autre chose pour indiquer au serveur que les colonnes peuvent être utilisées pour la commande. Il y a plusieurs façons de le faire, mais cette approche devrait fonctionner correctement:

SELECT rsc.RadioServiceCodeId,
            rsc.RadioServiceCode + ' - ' + rsc.RadioService as RadioService
FROM sbi_l_radioservicecodes rsc
INNER JOIN sbi_l_radioservicecodegroups rscg 
    ON rsc.radioservicecodeid = rscg.radioservicecodeid
WHERE rscg.radioservicegroupid IN 
    (SELECT val FROM dbo.fnParseArray(@RadioServiceGroup,','))
    OR @RadioServiceGroup IS NULL  
GROUP BY rsc.RadioServiceCode,rsc.RadioServiceCodeId,rsc.RadioService
ORDER BY rsc.RadioServiceCode,rsc.RadioServiceCodeId,rsc.RadioService
47
Joel Coehoorn

Essayez l'une de celles-ci:

  1. Utilisez un alias de colonne:

    ORDER BY RadioServiceCodeId, RadioService

  2. Utiliser la position de la colonne:

    COMMANDER PAR 1,2

Vous ne pouvez trier que les colonnes qui apparaissent réellement dans le résultat de la requête DISTINCT - les données sous-jacentes ne sont pas disponibles pour la commande.

11
Tony Andrews

Lorsque vous définissez la concaténation, vous devez utiliser un programme ALIAS pour la nouvelle colonne si vous souhaitez y placer une commande combinée à DISTINCT Some Ex avec SQL 2008

--this works 

    SELECT DISTINCT (c.FirstName + ' ' + c.LastName) as FullName 
    from SalesLT.Customer c 
    order by FullName

--this works too

    SELECT DISTINCT (c.FirstName + ' ' + c.LastName) 
    from SalesLT.Customer c 
    order by 1

-- this doesn't 

    SELECT DISTINCT (c.FirstName + ' ' + c.LastName) as FullName 
    from SalesLT.Customer c 
    order by c.FirstName, c.LastName

-- the problem the DISTINCT needs an order on the new concatenated column, here I order on the singular column
-- this works

    SELECT DISTINCT (c.FirstName + ' ' + c.LastName) 
        as FullName, CustomerID 
        from SalesLT.Customer c 

order by 1, CustomerID

-- this doesn't

    SELECT DISTINCT (c.FirstName + ' ' + c.LastName) as FullName 
     from SalesLT.Customer c 
      order by 1, CustomerID
3
rio

Distinct et Group By font généralement le même genre de choses, à des fins différentes ... Ils créent tous deux une table "de travail" en mémoire en fonction des colonnes groupées sur (ou sélectionnées dans la clause Select Distinct) - puis remplissent cette table de travail pendant que la requête lit les données, en ajoutant une nouvelle "ligne" uniquement lorsque les valeurs indiquent la nécessité de le faire ...

La seule différence est que, dans le groupe, il y a des "colonnes" supplémentaires dans la table de travail pour tous les champs agrégés calculés, tels que Sum (), Count (), Avg (), etc., qui doivent être mis à jour pour chaque ligne d'origine lue. Distinct n'a pas à faire cela ... Dans le cas particulier où vous groupez uniquement pour obtenir des valeurs distinctes (et il n'y a pas de colonnes d'agrégat en sortie), il s'agit probablement du même plan de requête .... Il Il serait intéressant d'examiner le plan d'exécution de la requête pour les deux options et voir ce qu'il a fait ...

Si vous le souhaitez, la lisibilité est assurément distincte (si votre objectif est d'éliminer les lignes en double et que vous ne calculez aucune colonne d'agrégat)

3
Charles Bretana

Vous pouvez essayer une sous-requête:

SELECT DISTINCT TEST.* FROM (
    SELECT rsc.RadioServiceCodeId,
        rsc.RadioServiceCode + ' - ' + rsc.RadioService as RadioService
    FROM sbi_l_radioservicecodes rsc
       INNER JOIN sbi_l_radioservicecodegroups rscg ON  rsc.radioservicecodeid = rscg.radioservicecodeid
    WHERE rscg.radioservicegroupid IN 
       (select val from dbo.fnParseArray(@RadioServiceGroup,','))
        OR @RadioServiceGroup IS NULL  
    ORDER BY rsc.RadioServiceCode,rsc.RadioServiceCodeId,rsc.RadioService
) as TEST
0
HenryS