Подсчет различных по нескольким столбцам
есть ли лучший способ сделать такой запрос:
SELECT COUNT(*)
FROM (SELECT DISTINCT DocumentId, DocumentSessionId
FROM DocumentOutputItems) AS internalQuery
Мне нужно подсчитать количество различных элементов из этой таблицы, но distinct более двух столбцов.
мой запрос работает нормально, но мне было интересно, могу ли я получить конечный результат, используя только один запрос (без использования подзапроса)
16 ответов:
Если вы пытаетесь повысить производительность, вы можете попробовать создать сохраненный вычисляемый столбец либо на хэше, либо на объединенном значении двух столбцов.
Как только он сохраняется, при условии, что столбец детерминирован, и вы используете "нормальные" настройки базы данных, он может быть проиндексирован и / или статистика может быть создана на нем.
Я считаю, что отдельный счетчик вычисляемого столбца будет эквивалентен вашему запросу.
изменить: изменено из менее чем надежного запроса контрольной суммы Я нашел способ сделать это (в SQL Server 2005), который работает довольно хорошо для меня, и я могу использовать столько столбцов, сколько мне нужно (добавив их в функцию CHECKSUM ()). Функция REVERSE () превращает ints в varchars, чтобы сделать distinct более надежным
SELECT COUNT(DISTINCT (CHECKSUM(DocumentId,DocumentSessionId)) + CHECKSUM(REVERSE(DocumentId),REVERSE(DocumentSessionId)) ) FROM DocumentOutPutItems
что вам не нравится в вашем существующем запросе? Если вы обеспокоены тем, что
DISTINCTчерез два столбца не возвращает только уникальные перестановки, почему бы не попробовать?Это, конечно, работает, как вы могли бы ожидать в 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>edit
я пошел в тупик с аналитикой, но ответ был удручающе очевиден...
SQL> select count(distinct concat(deptno,job)) from emp 2 / COUNT(DISTINCTCONCAT(DEPTNO,JOB)) --------------------------------- 9 SQL>edit 2
учитывая следующие данные в обьединении решение, предложенное выше, ошибаетесь:
col1 col2 ---- ---- A AA AA Aпоэтому мы включим разделитель...
select col1 + '*' + col2 from t23 /очевидно, что выбранный разделитель должен быть символом или набором символов, которые никогда не могут отображаться ни в одном столбце.
Как насчет чего-то вроде:
select count(*) from (select count(*) cnt from DocumentOutputItems group by DocumentId, DocumentSessionId) t1вероятно, просто делает то же самое, что вы уже, хотя, но это позволяет избежать различных.
чтобы выполнить как один запрос, объедините столбцы, а затем получите отличное количество экземпляров объединенной строки.
SELECT count(DISTINCT concat(DocumentId, DocumentSessionId)) FROM DocumentOutputItems;в MySQL вы можете сделать то же самое без шага конкатенации следующим образом:
SELECT count(DISTINCT DocumentId, DocumentSessionId) FROM DocumentOutputItems;эта функция упоминается в документации MySQL:
http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_count-distinct
вот более короткая версия без подзапроса:
SELECT COUNT(DISTINCT DocumentId, DocumentSessionId) FROM DocumentOutputItemsон отлично работает в MySQL, и я думаю, что оптимизатор имеет более легкое понимание этого.
Edit: по-видимому, я неправильно понял MSSQL и MySQL - извините за это, но, возможно, это все равно помогает.
Я нашел это, когда я погуглил для своей собственной проблемы, обнаружил, что если вы считаете разные объекты, вы получаете правильное число (я использую MySQL)
SELECT COUNT(DISTINCT DocumentID) AS Count1, COUNT(DISTINCT DocumentSessionId) AS Count2 FROM DocumentOutputItems
в вашем запросе нет ничего плохого, но вы также можете сделать это следующим образом:
WITH internalQuery (Amount) AS ( SELECT (0) FROM DocumentOutputItems GROUP BY DocumentId, DocumentSessionId ) SELECT COUNT(*) AS NumberOfDistinctRows FROM internalQuery
если бы у вас было только одно поле для "DISTINCT", вы могли бы использовать:
SELECT COUNT(DISTINCT DocumentId) FROM DocumentOutputItemsи это возвращает тот же план запроса, что и оригинал, как проверено с SET SHOWPLAN_ALL ON. Однако вы используете два поля, так что вы можете попробовать что-то сумасшедшее, как:
SELECT COUNT(DISTINCT convert(varchar(15),DocumentId)+'|~|'+convert(varchar(15), DocumentSessionId)) FROM DocumentOutputItemsно у вас будут проблемы, если будут задействованы нули. Я бы просто придерживался исходного запроса.
надеюсь, что это работает я пишу на prima vista
SELECT COUNT(*) FROM DocumentOutputItems GROUP BY DocumentId, DocumentSessionId
Я хотел бы, чтобы MS SQL также мог делать что-то вроде COUNT(DISTINCT A, B). Но это невозможно.
сначала ответ ДжейТи показался мне решением, но после некоторых тестов контрольная сумма () не смогла создать уникальные значения. Быстрый пример, как контрольная сумма (31,467,519) и контрольная сумма(69,1120,823) дает тот же ответ, который составляет 55.
затем я провел некоторые исследования и обнаружил, что Microsoft не рекомендует использовать контрольную сумму для целей обнаружения изменений. На некоторых форумах некоторые предложили использовать
SELECT COUNT(DISTINCT CHECKSUM(value1, value2, ..., valueN) + CHECKSUM(valueN, value(N-1), ..., value1))но это тоже не conforting.
вы можете использовать функцию HASHBYTES (), как это предлагается в TSQL CHECKSUM conundrum. Однако это также имеет небольшой шанс не возвращать уникальные результаты.
Я бы предложил использовать
SELECT COUNT(DISTINCT CAST(DocumentId AS VARCHAR)+'-'+CAST(DocumentSessionId AS VARCHAR)) FROM DocumentOutputItems
многие (большинство?) Базы данных SQL могут работать с кортежами, такими как значения, поэтому вы можете просто сделать:
SELECT COUNT(DISTINCT (DocumentId, DocumentSessionId)) FROM DocumentOutputItems;Если ваша база данных не поддерживает это, она может быть смоделирована в соответствии с предложением @oncel-umut-turer о контрольной сумме или другой скалярной функции, обеспечивающей хорошую уникальность, напримерCOUNT(DISTINCT CONCAT(DocumentId, ':', DocumentSessionId)).соответствующее использование кортежей выполняется
INзапросы, такие как:SELECT * FROM DocumentOutputItems WHERE (DocumentId, DocumentSessionId) in (('a', '1'), ('b', '2'));
это работает для меня. В oracle:
SELECT SUM(DECODE(COUNT(*),1,1,1)) FROM DocumentOutputItems GROUP BY DocumentId, DocumentSessionId;в jpql:
SELECT SUM(CASE WHEN COUNT(i)=1 THEN 1 ELSE 1 END) FROM DocumentOutputItems i GROUP BY i.DocumentId, i.DocumentSessionId;
Как насчет этого,
Select DocumentId, DocumentSessionId, count(*) as c from DocumentOutputItems group by DocumentId, DocumentSessionId;Это даст нам количество всех возможных комбинаций DocumentId, и DocumentSessionId
вы можете просто использовать функцию Count дважды.
в этом случае, это будет выглядеть так:
выберите COUNT (DISTINCT DocumentId), COUNT (DISTINCT DocumentSessionId) из DocumentOutputItems
Это было поставлено и ответил на 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Я работал над этим в SAS, и SAS Proc SQL не любит DISTINCT с более чем одним столбцом.
Comments