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
J'ai besoin de compter le nombre d'éléments 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 une seule requête (sans utiliser de sous-requête)
sql
sql-server
performance
tsql
query-optimization
Novitzky
la source
la source
Réponses:
Si vous essayez d'améliorer les performances, vous pouvez essayer de créer une colonne calculée persistante sur un hachage ou une valeur 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 "sains", elle peut être indexée et / ou des statistiques peuvent être créées dessus.
Je crois qu'un nombre distinct de la colonne calculée serait équivalent à votre requête.
la source
Edit: Modifié 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 que nécessaire (en les ajoutant à la fonction CHECKSUM ()). La fonction REVERSE () transforme les entiers en varchars pour rendre le distinct plus fiable
la source
Qu'est-ce que vous n'aimez pas dans votre requête existante? Si vous craignez que
DISTINCT
sur deux colonnes ne renvoie pas uniquement les permutations uniques, pourquoi ne pas l'essayer?Cela fonctionne certainement comme vous pouvez vous y attendre dans Oracle.
Éditer
Je suis descendu dans une ruelle aveugle avec des analyses mais la réponse était d'une évidence déprimante ...
modifier 2
Compte tenu des données suivantes, la solution de concaténation fournie ci-dessus sera incorrecte:
Nous devons donc inclure un séparateur ...
Évidemment, le séparateur choisi doit être un caractère, ou un ensemble de caractères, qui ne peut jamais apparaître dans aucune des colonnes.
la source
Pour exécuter en tant que requête unique, concaténez les colonnes, puis obtenez le nombre distinct d'instances de la chaîne concaténée.
Dans MySQL, vous pouvez faire la même chose sans l'étape de concaténation comme suit:
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
la source
SELECT COUNT(DISTINCT (DocumentId, DocumentSessionId)) FROM DocumentOutputItems;
Que diriez-vous de quelque chose comme:
Fait probablement la même chose que vous êtes déjà, mais cela évite le DISTINCT.
la source
GROUP BY
peut introduire quelques défis supplémentaires à la transformation de la requête pour atteindre la sortie souhaitée (par exemple, lorsque la requête d'origine avait déjà des clausesGROUP BY
ou desHAVING
clauses ...)Voici une version plus courte sans la sous-sélection:
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 lu MSSQL et MySQL - désolé, mais peut-être que cela aide de toute façon.
la source
count ( distinct CHECKSUM ([Field1], [Field2])
De nombreuses bases de données SQL (la plupart?) Peuvent fonctionner avec des tuples comme des valeurs, vous pouvez donc simplement le faire:
SELECT COUNT(DISTINCT (DocumentId, DocumentSessionId)) FROM DocumentOutputItems;
si votre base de données ne le prend pas en charge, il peut être simulé selon la suggestion de @ oncel-umut-turer de CHECKSUM ou d'une autre fonction scalaire offrant une bonne unicité par exempleCOUNT(DISTINCT CONCAT(DocumentId, ':', DocumentSessionId))
.Une utilisation connexe des tuples effectue des
IN
requêtes telles que:SELECT * FROM DocumentOutputItems WHERE (DocumentId, DocumentSessionId) in (('a', '1'), ('b', '2'));
la source
select count(distinct(a, b))
? : DIl n'y a rien de mal à votre requête, mais vous pouvez également le faire de cette façon:
la source
J'espère que cela fonctionne, j'écris sur prima vista
la source
J'ai utilisé cette approche et cela a fonctionné pour moi.
Pour mon cas, il fournit un résultat correct.
la source
si vous n'aviez qu'un seul champ à "DISTINCT", vous pourriez utiliser:
et cela retourne le même plan de requête que l'original, comme testé avec SET SHOWPLAN_ALL ON. Cependant, vous utilisez deux champs afin que vous puissiez essayer quelque chose de fou comme:
mais vous aurez des problèmes si des NULL sont impliqués. Je m'en tiendrai à la requête d'origine.
la source
J'ai trouvé cela lorsque j'ai recherché mon propre problème sur Google, j'ai constaté que si vous comptez les objets DISTINCT, vous obtenez le bon nombre retourné (j'utilise MySQL)
la source
DocumentId
etDocumentSessionId
). Alexander Kjäll a déjà publié la bonne réponse si l'OP utilisait MySQL et non MS SQL Server.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 m'a semblé être une solution mais après que certains tests, CHECKSUM () n'a pas réussi à créer des valeurs uniques. Un exemple rapide est que CHECKSUM (31 467 519) et CHECKSUM (69 1 120 823) donnent la même réponse qui est 55.
Ensuite, j'ai fait des recherches et j'ai découvert que Microsoft ne recommande PAS d'utiliser CHECKSUM à des fins de détection des modifications. Dans certains forums, certains ont suggéré d'utiliser
mais ce n'est pas non plus réconfortant.
Vous pouvez utiliser la fonction HASHBYTES () comme suggéré dans l' énigme TSQL CHECKSUM . Cependant, cela a également une petite chance de ne pas renvoyer de résultats uniques.
Je suggère d'utiliser
la source
Que dis-tu de ça,
Cela nous donnera le nombre de toutes les combinaisons possibles de DocumentId et DocumentSessionId
la source
Ça marche pour moi. Dans l'oracle:
En jpql:
la source
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:
ignorant la complexité de cela, je me suis rendu compte que je ne pouvais pas obtenir la valeur de a.code dans la sous-requête avec la double sous-requête décrite dans la question d'origine
Finalement, j'ai compris que je pouvais tricher et combiner les colonnes:
C'est ce qui a fini par fonctionner
la source
Si vous travaillez avec des types de données de longueur fixe, vous pouvez effectuer un cast pour
binary
le faire très facilement et très rapidement. En supposantDocumentId
etDocumentSessionId
sont tous deuxint
s, et sont donc de 4 octets de long ...Mon problème spécifique m'obligeait à diviser un
SUM
par leCOUNT
de la combinaison distincte de diverses clés étrangères et d'un champ de date, regroupé par une autre clé étrangère et parfois filtré par certaines valeurs ou clés. Le tableau est très volumineux et l'utilisation d'une sous-requête a considérablement augmenté le temps de requête. Et en raison de la complexité, les statistiques n'étaient tout simplement pas une option viable. LaCHECKSUM
solution était également beaucoup trop lente dans sa conversion, notamment en raison des différents types de données, et je ne pouvais pas risquer son manque de fiabilité.Cependant, l'utilisation de la solution ci-dessus n'a pratiquement pas augmenté le temps de requête (comparé à l'utilisation de simplement
SUM
) et devrait être complètement fiable! Il devrait pouvoir aider d'autres personnes dans une situation similaire, alors je le poste ici.la source
Vous pouvez simplement utiliser la fonction de comptage deux fois.
Dans ce cas, ce serait:
la source
Ce code utilise distinct sur 2 paramètres et fournit le nombre de lignes spécifiques à ces valeurs distinctes. Cela a fonctionné pour moi dans MySQL comme un charme.
la source