Comptage DISTINCT sur plusieurs colonnes

Est-il une meilleure façon de faire une requête comme ceci:

SELECT COUNT(*) 
FROM (SELECT DISTINCT DocumentId, DocumentSessionId
      FROM DocumentOutputItems) AS internalQuery

je dois compter le nombre d'articles distincts de ce tableau, mais le distinct est sur deux colonnes.

ma requête fonctionne bien mais je me demandais si je pouvais obtenir le résultat final en utilisant juste une requête (sans utiliser une sous-requête)

148
demandé sur Jeff 2009-09-24 16:03:50

16 réponses

si vous essayez d'améliorer la performance, vous pouvez essayer de créer une colonne persisted computed sur soit un hachage ou concatenated valeur des deux colonnes.

une fois qu'il est persisté, à condition que la colonne est déterministe et que vous utilisez des paramètres de base de données "sains", il peut être indexé et / ou des statistiques peuvent être créées sur elle.

je crois qu'un nombre distinct de la colonne calculée serait équivalent à votre requête.

54
répondu JasonHorner 2016-07-27 19:18:01

Edit: Modifié à partir de la moins-que-la fiabilité de la somme de contrôle seule requête J'ai découvert une façon de faire cela (dans SQL Server 2005) qui fonctionne assez bien pour moi et je peux utiliser autant de colonnes que j'ai besoin (en les ajoutant à la fonction CHECKSUM ()). La fonction REVERSE () transforme les ints en varchars pour rendre le distinct plus fiable ""

SELECT COUNT(DISTINCT (CHECKSUM(DocumentId,DocumentSessionId)) + CHECKSUM(REVERSE(DocumentId),REVERSE(DocumentSessionId)) )
FROM DocumentOutPutItems
45
répondu JayTee 2014-09-04 14:01:16

Qu'est-ce que votre requête existante que vous n'aimez pas? Si vous êtes préoccupé que DISTINCT à travers deux colonnes ne renvoie pas seulement les permutations uniques pourquoi ne pas essayer?

cela fonctionne certainement comme vous pourriez vous attendre 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 des analyses, mais la réponse était déprimante évidente...

SQL> select count(distinct concat(deptno,job)) from emp
  2  /

COUNT(DISTINCTCONCAT(DEPTNO,JOB))
---------------------------------
                                9

SQL>

edit 2

étant donné les données suivantes, la solution de concaténation fournie ci-dessus ne tiendra pas compte:

col1  col2
----  ----
A     AA
AA    A

donc nous devons inclure un séparateur...

select col1 + '*' + col2 from t23
/

Évidemment, le séparateur choisi doit être un caractère ou ensemble de caractères, qui ne peut jamais apparaître dans la colonne.

19
répondu APC 2012-04-19 06:15:15

Que Diriez-vous de quelque chose comme:

select count(*)
from
  (select count(*) cnt
   from DocumentOutputItems
   group by DocumentId, DocumentSessionId) t1

fait probablement juste la même chose que vous êtes déjà bien que, mais il évite le DISTINCT.

13
répondu Trevor Tippins 2009-09-24 12:57:53

pour exécuter une requête simple, concaténer les colonnes, puis obtenir le nombre distinct d'instances 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/en/group-by-functions.html#function_count-distinct

6
répondu spelunk1 2016-07-28 20:21:27

Voici une version plus courte sans le sous-select:

SELECT COUNT(DISTINCT DocumentId, DocumentSessionId) FROM DocumentOutputItems

cela fonctionne très bien à MySQL, et je pense que l'optimiseur a un temps plus facile de comprendre celui-ci.

Edit: apparemment j'ai mal lu MSSQL et MySQL - désolé pour ça, mais peut-être que ça aide quand même.

6
répondu Alexander Kjäll 2016-12-01 10:40:06

j'ai trouvé ceci quand J'ai googlé pour mon propre problème, trouvé que si vous comptez les objets distincts, vous obtenez le nombre correct retourné (J'utilise MySQL)

SELECT COUNT(DISTINCT DocumentID) AS Count1, 
  COUNT(DISTINCT DocumentSessionId) AS Count2
  FROM DocumentOutputItems
4
répondu tehaugmenter 2013-04-12 16:31:07

il n'y a rien de mal à votre requête, 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
3
répondu Bliek 2009-09-24 13:37:10

si vous n'aviez qu'un champ pour "distinguer", vous pourriez utiliser:

SELECT COUNT(DISTINCT DocumentId) 
FROM DocumentOutputItems

et qui renvoie le même plan de requête que l'original, tel que Testé avec SET SHOWPLAN_ALL on. Cependant, vous utilisez deux champs pour 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 NULLs sont impliqués. Je m'en tiendrais à la requête originale.

2
répondu KM. 2009-09-24 13:34:03

Espère que cela fonctionne, je suis en train d'écrire sur le prima vista

SELECT COUNT(*) 
FROM DocumentOutputItems 
GROUP BY DocumentId, DocumentSessionId
2
répondu IordanTanev 2013-03-07 12:49:22

j'aimerais que Mme SQL puisse aussi faire quelque chose comme COUNT(DISTINCT A, B). Mais c'est impossible.

au début, la réponse de JayTee m'a semblé être une solution, mais après quelques tests, CHECKSUM() n'a pas réussi à créer des valeurs uniques. Un exemple rapide est, à la fois CHECKSUM(31,467,519) et CHECKSUM(69,1120,823) donne la même réponse qui est 55.

puis j'ai fait quelques recherches et j'ai constaté que Microsoft ne recommande pas l'utilisation de CHECKSUM pour la détection de changement. Certaines 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 convaincant.

vous pouvez utiliser la fonction HASHBYTES() comme suggéré dans TSQL CHECKSUM conundrum . Toutefois, cela a également une petite chance de ne pas retourner des résultats uniques.

je suggérerais d'utiliser

SELECT COUNT(DISTINCT CAST(DocumentId AS VARCHAR)+'-'+CAST(DocumentSessionId AS VARCHAR)) FROM DocumentOutputItems
1
répondu Oncel Umut TURER 2017-05-23 11:47:21

beaucoup (la plupart?) Les bases de données SQL peuvent fonctionner avec des valeurs comme tuples donc vous pouvez juste faire: SELECT COUNT(DISTINCT (DocumentId, DocumentSessionId)) FROM DocumentOutputItems; Si votre base de données ne supporte pas cela, il peut être simulé selon la suggestion de CHECKSUM de @oncel-umut-turer ou d'une autre fonction scalaire fournissant une bonne unicité par exemple COUNT(DISTINCT CONCAT(DocumentId, ':', DocumentSessionId)) .

une utilisation connexe de tuples est d'effectuer des requêtes IN telles que: SELECT * FROM DocumentOutputItems WHERE (DocumentId, DocumentSessionId) in (('a', '1'), ('b', '2'));

1
répondu karmakaze 2018-06-02 16:42:25

ça me va. 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;
0
répondu Nata 2018-03-29 07:59:14

que dis-tu de ça,

Select DocumentId, DocumentSessionId, count(*) as c 
from DocumentOutputItems 
group by DocumentId, DocumentSessionId;

cela nous donnera le compte de toutes les combinaisons possibles de DocumentId, et DocumentSessionId

0
répondu Nikhil Singh 2018-05-01 10:57:35

vous pouvez simplement utiliser la fonction Count deux fois.

Dans ce cas, ce serait:

sélectionnez COUNT (DISTINCT DocumentId), COUNT (DISTINCT DocumentSessionId) FROM DocumentOutputItems

0
répondu Bibek 2018-08-14 16:11:36

cela a été posé et répondu sur Quora ( https://www.quora.com/In-SQL-how-to-I-count-DISTINCT-over-multiple-columns ):

select col1, col2, col3, count(*)
from table
group by col1, col2, col3

je travaillais sur ce dans SAS, et SAS PROC SQL n'aime pas DISTINCT avec plus d'une colonne.

-3
répondu Barry DeCicco 2016-09-20 20:12:10