Подсчет различных по нескольким столбцам



есть ли лучший способ сделать такой запрос:



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


Мне нужно подсчитать количество различных элементов из этой таблицы, но distinct более двух столбцов.



мой запрос работает нормально, но мне было интересно, могу ли я получить конечный результат, используя только один запрос (без использования подзапроса)

597   16  

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

    Ничего не найдено.