Existe-t-il une meilleure façon de faire une requête comme celle-ci:
SELECT COUNT(*)
FROM (SELECT DISTINCT DocumentId, DocumentSessionId
FROM DocumentOutputItems) AS internalQuery
Je dois compter le nombre d'éléments distincts de ce tableau, mais le nombre distinct est supérieur à deux colonnes.
Ma requête fonctionne bien mais je me demandais si je pouvais obtenir le résultat final en utilisant une seule requête (sans utiliser une sous-requête)
Si vous essayez d’améliorer les performances, vous pouvez essayer de créer une colonne calculée persistante sur une valeur de hachage ou concaténée des deux colonnes.
Une fois qu'elle est persistante, à condition que la colonne soit déterministe et que vous utilisiez des paramètres de base de données "sane", vous pouvez l'indexer et/ou créer des statistiques.
Je crois qu'un compte distinct de la colonne calculée serait équivalent à votre requête.
Modification: modification de la requête de somme de contrôle moins que fiable J'ai découvert un moyen de le faire (dans SQL Server 2005) qui fonctionne assez bien pour moi et je peux utiliser autant de colonnes J'ai besoin (en les ajoutant à la fonction CHECKSUM ()). La fonction REVERSE () transforme les ints en varchars pour améliorer la fiabilité
SELECT COUNT(DISTINCT (CHECKSUM(DocumentId,DocumentSessionId)) + CHECKSUM(REVERSE(DocumentId),REVERSE(DocumentSessionId)) )
FROM DocumentOutPutItems
Qu'est-ce qui vous déplaît dans votre requête existante? Si vous pensez que DISTINCT
sur deux colonnes ne renvoie pas uniquement les permutations uniques, pourquoi ne pas l'essayer?
Cela fonctionne certainement comme prévu dans Oracle.
SQL> select distinct deptno, job from emp
2 order by deptno, job
3 /
DEPTNO JOB
---------- ---------
10 CLERK
10 MANAGER
10 PRESIDENT
20 ANALYST
20 CLERK
20 MANAGER
30 CLERK
30 MANAGER
30 SALESMAN
9 rows selected.
SQL> select count(*) from (
2 select distinct deptno, job from emp
3 )
4 /
COUNT(*)
----------
9
SQL>
modifier
Je suis allé dans une impasse avec les analyses mais la réponse était terriblement évidente ...
SQL> select count(distinct concat(deptno,job)) from emp
2 /
COUNT(DISTINCTCONCAT(DEPTNO,JOB))
---------------------------------
9
SQL>
modifier 2
Compte tenu des données suivantes, la solution de concaténation fournie ci-dessus comptera de manière erronée:
col1 col2
---- ----
A AA
AA A
Nous devons donc inclure un séparateur ...
select col1 + '*' + col2 from t23
/
De toute évidence, le séparateur choisi doit être un caractère, ou un ensemble de caractères, qui ne peuvent jamais apparaître dans l'une ou l'autre colonne.
Que diriez-vous de quelque chose comme:
sélectionner le compte (*) à partir de (sélectionnez count (*) cnt à partir de DocumentOutputItems groupe par DocumentId, DocumentSessionId) t1
Probablement juste fait la même chose que vous êtes déjà mais cela évite le DISTINCT.
Pour exécuter une requête unique, concaténez les colonnes, puis obtenez le nombre d'instances distinct de la chaîne concaténée.
SELECT count(DISTINCT concat(DocumentId, DocumentSessionId)) FROM DocumentOutputItems;
Dans MySQL, vous pouvez faire la même chose sans l'étape de concaténation comme suit:
SELECT count(DISTINCT DocumentId, DocumentSessionId) FROM DocumentOutputItems;
Cette fonctionnalité est mentionnée dans la documentation MySQL:
http://dev.mysql.com/doc/refman/5.7/fr/group-by-functions.html#function_count-distinct
Voici une version plus courte sans la sous-sélection:
SELECT COUNT(DISTINCT DocumentId, DocumentSessionId) FROM DocumentOutputItems
Cela fonctionne très bien dans MySQL, et je pense que l'optimiseur a plus de facilité à comprendre celui-ci.
Edit: Apparemment, j'ai mal interprété MSSQL et MySQL - désolé, mais peut-être que ça aide quand même.
J'ai trouvé cela quand j'ai cherché sur Google pour mon propre problème. J'ai constaté que si vous comptez les objets DISTINCT, vous obtenez le nombre correct renvoyé (j'utilise MySQL).
SELECT COUNT(DISTINCT DocumentID) AS Count1,
COUNT(DISTINCT DocumentSessionId) AS Count2
FROM DocumentOutputItems
Votre requête n'a rien d'anormal, mais vous pouvez aussi le faire de cette façon:
WITH internalQuery (Amount)
AS
(
SELECT (0)
FROM DocumentOutputItems
GROUP BY DocumentId, DocumentSessionId
)
SELECT COUNT(*) AS NumberOfDistinctRows
FROM internalQuery
J'espère que cela fonctionne, j'écris sur prima Vista
SELECT COUNT(*)
FROM DocumentOutputItems
GROUP BY DocumentId, DocumentSessionId
si vous ne possédez qu'un seul champ pour "DISTINCT", vous pouvez utiliser:
SELECT COUNT(DISTINCT DocumentId)
FROM DocumentOutputItems
et cela renvoie le même plan de requête que l'original, testé avec SET SHOWPLAN_ALL ON. Cependant, vous utilisez deux champs afin que vous puissiez essayer quelque chose de fou comme:
SELECT COUNT(DISTINCT convert(varchar(15),DocumentId)+'|~|'+convert(varchar(15), DocumentSessionId))
FROM DocumentOutputItems
mais vous aurez des problèmes si NULL sont impliqués. Je resterais juste avec la requête originale.
Beaucoup de bases de données SQL (la plupart?) Peuvent fonctionner avec des nuplets comme des valeurs. Vous pouvez donc simplement:
SELECT COUNT(DISTINCT (DocumentId, DocumentSessionId))
FROM DocumentOutputItems;
Si votre base de données ne le supporte pas, elle peut être simulée selon la suggestion de CHECKSUM de @ oncel-umut-turer ou une autre fonction scalaire offrant une bonne unicité, par exemple
COUNT(DISTINCT CONCAT(DocumentId, ':', DocumentSessionId))
.
Une utilisation connexe des n-uplets consiste à exécuter des requêtes IN
telles que:
SELECT * FROM DocumentOutputItems
WHERE (DocumentId, DocumentSessionId) in (('a', '1'), ('b', '2'));
Je souhaite que MS SQL puisse également faire quelque chose comme COUNT (DISTINCT A, B). Mais ça ne peut pas.
Au début, la réponse de JayTee semblait être une solution pour moi, mais après quelques tests, CHECKSUM () n'a pas réussi à créer des valeurs uniques. Un exemple rapide est que CHECKSUM (31 467 519) et CHECKSUM (69, 1120 823) donnent la même réponse, à savoir 55.
Après quelques recherches, j'ai constaté que Microsoft ne recommandait PAS d'utiliser CHECKSUM à des fins de détection des modifications. Dans certains forums, certains ont suggéré d'utiliser
SELECT COUNT(DISTINCT CHECKSUM(value1, value2, ..., valueN) + CHECKSUM(valueN, value(N-1), ..., value1))
mais ce n'est pas non plus rassurant.
Vous pouvez utiliser la fonction HASHBYTES () comme suggéré dans TSQL CHECKSUM conundrum . Cependant, cela a aussi une petite chance de ne pas renvoyer des résultats uniques.
Je suggère d'utiliser
SELECT COUNT(DISTINCT CAST(DocumentId AS VARCHAR)+'-'+CAST(DocumentSessionId AS VARCHAR)) FROM DocumentOutputItems
J'avais une question similaire mais la requête que j'avais était une sous-requête avec les données de comparaison dans la requête principale. quelque chose comme:
Select code, id, title, name
(select count(distinct col1) from mytable where code = a.code and length(title) >0)
from mytable a
group by code, id, title, name
--needs distinct over col2 as well as col1
ignorant la complexité de ceci, j'ai réalisé que je ne pouvais pas obtenir la valeur de a.code dans la sous-requête avec la requête double sous décrite dans la question initiale.
Select count(1) from (select distinct col1, col2 from mytable where code = a.code...)
--this doesn't work because the sub-query doesn't know what "a" is
Alors, finalement, j'ai compris que je pouvais tricher et combiner les colonnes:
Select count(distinct(col1 || col2)) from mytable where code = a.code...
C'est ce qui a fini par fonctionner
Vous pouvez simplement utiliser la fonction Compter deux fois.
Dans ce cas, ce serait:
SELECT COUNT (DISTINCT DocumentId), COUNT (DISTINCT DocumentSessionId)
FROM DocumentOutputItems
Que dis-tu de ça,
Select DocumentId, DocumentSessionId, count(*) as c
from DocumentOutputItems
group by DocumentId, DocumentSessionId;
Cela nous donnera le nombre de toutes les combinaisons possibles de DocumentId et DocumentSessionId
J'ai utilisé cette approche et cela a fonctionné pour moi.
SELECT COUNT(DISTINCT DocumentID || DocumentSessionId)
FROM DocumentOutputItems
Pour mon cas, le résultat est correct.
Ça marche pour moi. Dans Oracle:
SELECT SUM(DECODE(COUNT(*),1,1,1))
FROM DocumentOutputItems GROUP BY DocumentId, DocumentSessionId;
En jpql:
SELECT SUM(CASE WHEN COUNT(i)=1 THEN 1 ELSE 1 END)
FROM DocumentOutputItems i GROUP BY i.DocumentId, i.DocumentSessionId;