2016-11-04 6 views
1

Я унаследовал хранимую процедуру, которая использует переменную таблицы для хранения данных, а затем обновляет каждую строку с полным расчетным счетом. Порядок записей в переменной таблицы очень важен, так как мы хотим, чтобы объем заказывался с наивысшим наименьшим (т. Е. Общее количество работы будет увеличиваться по мере того, как вы идете вниз по таблице).Использование текущего подсчитанного столбца в переменной таблицы SQL Server

Моя проблема, во время стадии, где обновляется переменная таблица, общая сумма, кажется, вычисления, но не таким образом, что данные в таблице переменных была ранее отсортированный по (убывания высокий объем)

DECLARE @TableVariable TABLE ([ID], [Volume], [SortValue], [RunningTotal]) 

--Populate table variable and order by the sort value... 
INSERT INTO @TableVariable (ID, Volume, SortValue) 
    SELECT 
     [ID], [Volume], ABS([Volume]) as SortValue 
    FROM 
     dbo.VolumeTable 
    ORDER BY 
     SortValue DESC 

--Set TotalVolume variable... 
[email protected] = ABS(sum([Volume])) 
FROM @TableVariable 

--Calculate running total, update rows in table variable...I believe this is where problem occurs? 
SET @RunningTotal = 0 

UPDATE @TableVariable 
SET @RunningTotal = RunningTotal = @RunningTotal + [Volume] 
FROM @TableVariable 

--Output... 
SELECT 
    ID, Volume, SortValue, RunningTotal 
FROM  
    @TableVariable  
ORDER BY 
    SortValue DESC 

В результате запись, которая имела самый высокий том, я бы ожидал, что общая сумма будет вычисляться сначала (при этом общая сумма = [том]), как-то заканчивается намного дальше в списке. Нарастающим итогом, кажется, вычислить случайно

Вот что я хотел бы ожидать, чтобы получить:

Good result

Но вот что код на самом деле генерирует:

enter image description here

Не уверен, что если есть способ заставить оператор UPDATE быть введенным в переменную таблицы таким образом, что он упорядочен по объему desc? Из того, что Ive читал до сих пор, это может быть проблема с поведением сортировки переменной таблицы, но не уверен, как исправить? Может ли кто-нибудь помочь?

+4

Нет, не делайте этого. Вы используете то, что обычно называют причудливым методом обновления. Учитывая, что это переменная таблицы, я уже знаю, что вы нарушаете некоторые известные проблемы в этой технике. Для этой работы требуется кластеризованный индекс. Ознакомьтесь с этой статьей, в которой обсуждается этот метод. http://www.sqlservercentral.com/articles/T-SQL/68467/ Обязательно прочитайте комментарии. Этот подход недокументирован и является весьма противоречивым. Функции Windows подойдут вам лучше здесь. –

+1

[Лучшие подходы к запуску итогов - обновлено для SQL Server 2012] (https://sqlperformance.com/2012/07/t-sql-queries/running-totals) – GarethD

+0

Ваши изображения отображают тома отсортированы по убыванию, а покадровая сортировка по возрастанию , Я не вижу проблемы ... – Zack

ответ

2

Заглянуть в функции окна, предлагаемые в SQL

Например

Declare @YourTable table (ID int,Volume int) 
Insert Into @YourTable values 
(100,1306489), 
(125,898426), 
(150,907404) 

Select ID 
     ,Volume 
     ,RunningTotal = sum(Volume) over (Order by Volume Desc) 
From @YourTable 
Order By Volume Desc 

Возвращает

ID Volume RunningTotal 
100 1306489 1306489 
150 907404 2213893 
125 898426 3112319 

Чтобы было ясно, @YourTable для демонстрации только. Не нужно вставлять свои фактические данные в переменную таблицы.

EDIT для поддержки 2008 (Хорошие новости row_number() поддерживается в 2008 году)

Select ID 
     ,Volume 
     ,RowNr=Row_Number() over (Order by Volume Desc) 
    Into #Temp 
    From @YourTable 


Select A.ID 
     ,A.Volume 
     ,RunningTotal = sum(B.Volume) 
    From #Temp A 
    Join #Temp B on (B.RowNr<=A.RowNr) 
    Group By A.ID,A.Volume 
    Order By A.Volume Desc 
+0

Это может быть то, что я ищу, но я продолжаю получать сообщение об ошибке: Msg 11305, Level 15, State 10. В текущей строке вашего кода. мы используем SQL Server 2008 R2 и смотрим, что код ошибки в нем упоминает, что функции Parallel Datawarehouse не включены? – Spartan46236

+0

@ Spartan46236 К сожалению, Sum() Over не поддерживается в 2008 году. Дайте мне несколько минут, чтобы дать вам альтернативу –

+0

@ Spartan46236 См. EDIT в обновленном ответе –

1

GarethD обеспечил несомненную связь с несколькими способами расчета нарастающих итогов и их производительность , Правильный - самый простой и быстрый, 300 раз быстрее, чем причудливое обновление. Это потому, что он может использовать любые индексы, которые покрывают столбец сортировки, и потому что это намного проще.

Я повторяю это здесь, чтобы дать понять, насколько проще это, когда база данных при условии, что соответствующие оконных функции

SELECT 
    [Date], 
    TicketCount, 
    SUM(TicketCount) OVER (ORDER BY [Date] RANGE UNBOUNDED PRECEDING) 
FROM dbo.SpeedingTickets 
ORDER BY [Date]; 

означает, SUM линии: Сумма всех счетчиков билетов по всем (неограниченным) строкам, которые пришли раньше (PRECEDING) текущий, если они были заказаны по дате

Это заканчивается тем, что в 300 раз быстрее, чем причудливое обновление.

Эквивалентный запрос для VolumeTable будет:

SELECT 
    ID, 
    Volume, 
    ABS(Volume) as SortValue, 
    SUM(Volume) OVER (ORDER BY ABS(Volume) DESC RANGE UNBOUNDED PRECEDING) 
FROM 
    VolumeTable 
ORDER BY ABS(Volume) DESC 

Обратите внимание, что это будет намного быстрее, если есть индекс столбца сортировки (по объему), и ABS не используется. Применение любой функции в столбце означает, что оптимизатор не может использовать какие-либо индексы, которые его покрывают, поскольку фактическое значение сортировки отличается от того, которое хранится в индексе.

Если таблица очень большая и производительность страдает, вы можете создать вычисляемый столбец и создать индекс на нем

Смежные вопросы