Как следует из названия, мне нужна помощь в получении промежуточного итога в T-SQL. Проблема в том, что сумма, которую мне нужно сделать, это сумма счета:
sum(count (distinct (customers)))
Скажем, если бы я вел подсчет один, результат был бы:
Day | CountCustomers
----------------------
5/1 | 1
5/2 | 0
5/3 | 5
Мне нужен вывод с суммой:
Day | RunningTotalCustomers
----------------------
5/1 | 1
5/2 | 1
5/3 | 6
Я выполнил промежуточные итоги до использования coalesce
метода, но никогда с подсчетом. Я не уверен, как это сделать сейчас, когда у меня есть счет.
sql-server
t-sql
Аарон Бертран
источник
источник
Day
ли ключ и являются ли значения смежными?Ответы:
Вот несколько методов, которые вы можете сравнить. Сначала давайте настроим таблицу с некоторыми фиктивными данными. Я заполняю это кучей случайных данных из sys.all_columns. Ну, это как-то случайно - я гарантирую, что даты являются смежными (что действительно важно только для одного из ответов).
Полученные результаты:
Данные выглядят так (5000 строк), но в вашей системе они будут немного отличаться в зависимости от версии и номера сборки:
И результаты промежуточных итогов должны выглядеть следующим образом (501 строка):
Итак, методы, которые я собираюсь сравнить:
автообъединение
Именно так люди скажут вам сделать это, когда они предупреждают вас держаться подальше от курсоров, потому что «набор на основе всегда быстрее». В некоторых недавних экспериментах я обнаружил, что курсор опережает это решение.
рекурсивный cte с датами
Напоминание - это зависит от непрерывных дат (без пропусков), до 10000 уровней рекурсии и от того, что вы знаете дату начала интересующего диапазона (для установки привязки). Конечно, вы можете динамически устанавливать привязку, используя подзапрос, но я хотел, чтобы все было просто.
рекурсивный cte с row_number
Расчет Row_number здесь немного дороже. Опять же, это поддерживает максимальный уровень рекурсии 10000, но вам не нужно назначать привязку.
рекурсивный cte с временной таблицей
Кража из ответа Микаэля, как предлагалось, чтобы включить это в тесты.
необычное обновление
Опять же, я включил это только для полноты; Лично я бы не стал полагаться на это решение, поскольку, как я уже упоминал в другом ответе, этот метод совсем не гарантированно работает и может полностью сломаться в будущей версии SQL Server. (Я делаю все возможное, чтобы заставить SQL Server подчиняться желаемому порядку, используя подсказку для выбора индекса.)
курсор
«Осторожно, здесь есть курсоры! Курсоры - это зло! Вы должны избегать курсоров любой ценой!» Нет, это не я говорю, это просто вещи, которые я много слышу. Вопреки распространенному мнению, в некоторых случаях курсоры являются подходящими.
SQL Server 2012
Если вы работаете с самой последней версией SQL Server, усовершенствования функциональности управления окнами позволяют нам легко рассчитать промежуточные итоги без экспоненциальной стоимости самостоятельного объединения (SUM рассчитывается за один проход), сложности CTE (включая требование смежных строк для более эффективной работы CTE), неподдерживаемое причудливое обновление и запрещенный курсор. Просто будьте осторожны с разницей между использованием
RANGE
иROWS
, или вообще не указанием -ROWS
избегайте только спулинга на диске, который в противном случае значительно снизит производительность.сравнение производительности
Я взял каждый подход и упаковал его, используя следующее:
Вот результаты общей длительности в миллисекундах (помните, что это также включает команды DBCC каждый раз):
И я сделал это снова без команд DBCC:
Удаление DBCC и циклов, просто измерение одной необработанной итерации:
Наконец, я умножил количество строк в исходной таблице на 10 (изменив top на 50000 и добавив другую таблицу в качестве перекрестного соединения). Результаты этой одной итерации без команд DBCC (просто в интересах времени):
Я только измерил продолжительность - я оставлю это в качестве упражнения для читателя, чтобы сравнить эти подходы на их данных, сравнивая другие метрики, которые могут быть важными (или могут варьироваться в зависимости от их схемы / данных). Прежде чем делать какие-либо выводы из этого ответа, вам нужно будет проверить его на соответствие вашим данным и вашей схеме ... эти результаты почти наверняка изменятся по мере увеличения числа строк.
демонстрация
Я добавил sqlfiddle . Полученные результаты:
вывод
В моих тестах выбор был бы:
Но опять же, вы должны проверить их на соответствие вашей схеме и данным. Поскольку это был надуманный тест с относительно низким числом рядов, он также может быть пердеть на ветру. Я провел другие тесты с другой схемой и количеством строк, а эвристика производительности была совершенно другой ... именно поэтому я задал так много дополнительных вопросов к вашему первоначальному вопросу.
ОБНОВИТЬ
Я написал больше об этом здесь:
Лучшие подходы к подведению итогов - обновлено для SQL Server 2012
источник
Это, по-видимому, оптимальное решение
источник
day
Например, у вас должен быть кластерный индекс .Просто другой способ, дорогой, но независимый от версии. Он не использует временные таблицы или переменные.
источник