query - transact sql tutorial
Contando DISTINCT sobre múltiples columnas (15)
¿Qué pasa con su consulta existente que no le gusta? Si le preocupa que DISTINCT
en dos columnas no devuelva solo las permutaciones únicas, ¿por qué no intentarlo?
Ciertamente funciona como es de esperar en 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>
editar
Bajé por un callejón sin salida con análisis, pero la respuesta fue tristemente obvia ...
SQL> select count(distinct concat(deptno,job)) from emp
2 /
COUNT(DISTINCTCONCAT(DEPTNO,JOB))
---------------------------------
9
SQL>
editar 2
Teniendo en cuenta los siguientes datos, la solución de concatenación provista arriba contrastará:
col1 col2
---- ----
A AA
AA A
Entonces, para incluir un separador ...
select col1 + ''*'' + col2 from t23
/
Obviamente, el separador elegido debe ser un personaje, o conjunto de caracteres, que nunca puede aparecer en ninguna columna.
¿Hay una mejor manera de hacer una consulta como esta?
SELECT COUNT(*)
FROM (SELECT DISTINCT DocumentId, DocumentSessionId
FROM DocumentOutputItems) AS internalQuery
Necesito contar el número de elementos distintos de esta tabla, pero el distinto es más de dos columnas.
Mi consulta funciona bien pero me preguntaba si puedo obtener el resultado final con solo una consulta (sin usar una sub consulta)
¿Qué tal algo así como:
select count(*) from (select count(*) cnt from DocumentOutputItems group by DocumentId, DocumentSessionId) t1
Probablemente haga lo mismo que usted ya, pero evita el DISTINCT.
Aquí hay una versión más corta sin la subselección:
SELECT COUNT(DISTINCT DocumentId, DocumentSessionId) FROM DocumentOutputItems
Funciona bien en MySQL, y creo que al optimizador le resulta más fácil entenderlo.
Editar: Aparentemente, leí mal MSSQL y MySQL, disculpe por eso, pero tal vez ayude de todos modos.
Encontré esto cuando busqué en Google mi propio problema, encontré que si cuenta objetos DISTINCT, obtiene el número correcto devuelto (estoy usando MySQL)
SELECT COUNT(DISTINCT DocumentID) AS Count1,
COUNT(DISTINCT DocumentSessionId) AS Count2
FROM DocumentOutputItems
Espero que esto funcione, estoy escribiendo en prima vista
SELECT COUNT(*)
FROM DocumentOutputItems
GROUP BY DocumentId, DocumentSessionId
Esta consulta a continuación me funcionó en MySQL:
SELECT COUNT(DISTINCT col_1,col_2,..) from table_name;
Las columnas dadas en la consulta anterior viz. col_1, col_2 tiene una restricción UNIQUE
combinada en ellos. Eso significa que en mi tabla table_name
, he creado un índice UNIQUE
en col_1 + col_2
.
Esto fue planteado y respondido en 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
Estaba trabajando en esto en SAS, y SAS Proc SQL no le gusta DISTINCT con más de una columna.
Esto funciona para mi. En oráculo:
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;
No hay nada de malo con su consulta, pero también podría hacerlo de esta manera:
WITH internalQuery (Amount)
AS
(
SELECT (0)
FROM DocumentOutputItems
GROUP BY DocumentId, DocumentSessionId
)
SELECT COUNT(*) AS NumberOfDistinctRows
FROM internalQuery
Ojalá MS SQL también pudiera hacer algo como COUNT (DISTINCT A, B). Pero no puede.
Al principio, la respuesta de JayTee me pareció una solución, luego de algunas pruebas, CHECKSUM () no pudo crear valores únicos. Un ejemplo rápido es que tanto CHECKSUM (31,467,519) como CHECKSUM (69,1120,823) dan la misma respuesta que es 55.
Luego investigué y descubrí que Microsoft NO recomienda el uso de CHECKSUM para fines de detección de cambios. En algunos foros, algunos sugirieron usar
SELECT COUNT(DISTINCT CHECKSUM(value1, value2, ..., valueN) + CHECKSUM(valueN, value(N-1), ..., value1))
pero esto tampoco es cómodo.
Puede utilizar la función HASHBYTES () como se sugiere en el enigma TSQL CHECKSUM . Sin embargo, esto también tiene una pequeña posibilidad de no devolver resultados únicos.
Sugeriría usar
SELECT COUNT(DISTINCT CAST(DocumentId AS VARCHAR)+''-''+CAST(DocumentSessionId AS VARCHAR)) FROM DocumentOutputItems
Para ejecutar como una sola consulta, concatenar las columnas, luego obtener el recuento distinto de las instancias de la cadena concatenada.
SELECT count(DISTINCT concat(DocumentId, DocumentSessionId)) FROM DocumentOutputItems;
En MySQL puede hacer lo mismo sin el paso de concatenación de la siguiente manera:
SELECT count(DISTINCT DocumentId, DocumentSessionId) FROM DocumentOutputItems;
Esta característica se menciona en la documentación de MySQL:
http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_count-distinct
Qué tal esto,
Select DocumentId, DocumentSessionId, count(*) as c
from DocumentOutputItems
group by DocumentId, DocumentSessionId;
Esto nos dará la cuenta de todas las combinaciones posibles de DocumentId y DocumentSessionId
Si intenta mejorar el rendimiento, puede intentar crear una columna calculada persistente en un valor hash o concatenado de las dos columnas.
Una vez que se mantiene, siempre que la columna sea determinista y utilice una configuración de base de datos "sensata", puede indexarse y / o crearse estadísticas en ella.
Creo que un recuento distinto de la columna calculada sería equivalente a su consulta.
si tuvieras solo un campo para "DISTINCT", podrías usar:
SELECT COUNT(DISTINCT DocumentId)
FROM DocumentOutputItems
y eso devuelve el mismo plan de consulta que el original, tal como se probó con SET SHOWPLAN_ALL ON. Sin embargo, estás usando dos campos para que puedas probar algo loco como:
SELECT COUNT(DISTINCT convert(varchar(15),DocumentId)+''|~|''+convert(varchar(15), DocumentSessionId))
FROM DocumentOutputItems
pero tendrás problemas si hay NULL involucrados. Me quedaría con la consulta original.
Editar: alterado a partir de la consulta de suma de comprobación menos que confiable que he descubierto una forma de hacer esto (en SQL Server 2005) que funciona muy bien para mí y puedo usar tantas columnas como sea necesario (agregándolas a la función CHECKSUM ()). La función REVERSE () convierte las entradas en varchars para hacer que el distinto sea más confiable
SELECT COUNT(DISTINCT (CHECKSUM(DocumentId,DocumentSessionId)) + CHECKSUM(REVERSE(DocumentId),REVERSE(DocumentSessionId)) )
FROM DocumentOutPutItems