2014-11-21 3 views
1

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

У меня есть Travel стол -

ID  State  Days_Count Remaining_Days 
1   AL   20   - 
2   AL   2    - 
3   AL   14   - 

У меня есть еще один стол для Travel_Sum

State  Days_Sum Max_Limit Exceeding_Amt 
AL   36   12    24 

Есть несколько записей для других государств. Я пытаюсь написать один запрос, который будет обновлять оставшиеся дни с Exceeding_Amt. В этом примере значение столбца Exceeding_Amt равно 24. Таким образом, в первой таблице я пытаюсь обновить значение 20 (максимальное значение days_Count) против оставшихся дней, 2 против второй строки и (24-20-2) 2 против последней строки ,

В основном я должен разделить большее количество (т.е. 24) среди строк первой таблицы, где совпадение состояний. Итак, чтобы разделить 24, я хочу обновить оставшиеся_данные первой строки как 20. Потому что я не могу обновить значение, которое больше, чем days_count. У меня осталось 4 дня. Для второй строки, Days_count равно 2. Поэтому я обновил эту строку с помощью 2 (максимальное значение, которое мне разрешено ввести). В третьей строке я обновил значение столбца Remaining_Days с оставшимися 2 днями.

Желаемый результат:

ID  State  Days_Count Remaining_Days 
1   AL   20   20 
2   AL   2    2 
3   AL   14   2 

Этот вопрос может привести к путанице. Если это так, пожалуйста, дайте мне знать. Я постараюсь изо всех сил дать правильное понимание.

+1

Ну, для начала, вы можете написать результат, который вы хотите – Lamak

+0

Хорошо, я сделаю это за минуту – Kartic

+0

Это действительно сбивает с толку, но похоже, что вы можете быть после расчетного поля? –

ответ

3

Следующая должно работать для вас:

UPDATE t 
SET  Remaining_Days = CASE WHEN CumulativeDayCount < Exceeding_Amt THEN Days_Count 
           WHEN (CumulativeDayCount - Days_Count) > Exceeding_Amt THEN 0 
           ELSE Exceeding_Amt - (CumulativeDayCount - Days_Count) 
          END 
FROM ( SELECT t.ID, 
        t.Days_Count, 
        t.[State], 
        CumulativeDayCount = SUM(t.Days_Count) OVER(PARTITION BY t.[State] ORDER BY t.ID), 
        t.Remaining_Days, 
        ts.Exceeding_Amt 
      FROM Travel AS t 
        INNER JOIN Travel_Sum AS ts 
         ON ts.[State] = t.[State] 
     ) AS t; 

Основной шаг здесь, чтобы получить cumualtive количество дней, используя оконную функцию SUM() OVER():

SELECT t.ID, 
     t.Days_Count, 
     CumulativeDayCount = SUM(t.Days_Count) OVER(PARTITION BY t.[State] ORDER BY t.ID) 
FROM Travel AS t; 

Это дает:

ID Days_Count State CumulativeDayCount 
1 20   AL  20 
2 2   AL  22 
3 14   AL  36 

Затем вы можете присоединиться к вашей таблице суммы, чтобы получить Exceeding_Amt колонки, и работать ли все, некоторые, или ни один из этого не следует применять на основе совокупного объема.Это где выражение случай приходит в:

CASE WHEN CumulativeDayCount < Exceeding_Amt THEN Days_Count 
    WHEN (CumulativeDayCount - Days_Count) > Exceeding_Amt THEN 0 
    ELSE Exceeding_Amt - (CumulativeDayCount - Days_Count) 
END 

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

SELECT t.ID, 
     t.State, 
     t.Days_Count, 
     Remaining_Days = CASE WHEN CumulativeDayCount < Exceeding_Amt THEN Days_Count 
           WHEN (CumulativeDayCount - Days_Count) > Exceeding_Amt THEN 0 
           ELSE Exceeding_Amt - (CumulativeDayCount - Days_Count) 
          END 
FROM ( SELECT t.ID, 
        t.Days_Count, 
        t.[State], 
        CumulativeDayCount = SUM(t.Days_Count) OVER(PARTITION BY t.[State] ORDER BY t.ID), 
        ts.Exceeding_Amt 
      FROM Travel AS t 
        INNER JOIN Travel_Sum AS ts 
         ON ts.[State] = t.[State] 
     ) AS t; 

Example on SQL Fiddle

+1

Мне кажется, что 'SUM() OVER()' необходимо разделить на '[State]' – Lamak

+0

@Lamak. Вы правы, только тестирование с одним значением для состояния сделало меня неосторожным! Благодарю. – GarethD

+0

Большое спасибо! Я попробую и дам вам знать результат. – Kartic

0

Следующее использует подход CTE для запуска вычисления итогов.

DECLARE @Travel TABLE (ID INT, State VARCHAR(10), Days_Count INT) 
DECLARE @Travel_Sum TABLE (State VARCHAR(10), Exceeding_Amt INT) 

INSERT @Travel VALUES (1, 'AL', 20), (2, 'AL', 2), (3, 'AL', 14) 
INSERT @Travel_Sum VALUES ('AL', 24) 

;WITH TravelRows AS (
    SELECT 
     ID, 
     State, 
     Days_Count, 
     ROW_NUMBER() OVER (PARTITION BY State ORDER BY ID) AS RowNum 
    FROM @Travel 
), CTE AS (
    SELECT 
     TR.ID, 
     TR.State, 
     TR.Days_Count, 
     TR.RowNum, 
     TS.Exceeding_Amt - TR.Days_Count AS Exceeding_Amt, 
     CASE WHEN TS.Exceeding_Amt > TR.Days_Count THEN TR.Days_Count ELSE TS.Exceeding_Amt END AS Remaining_days 
    FROM TravelRows TR 
     INNER JOIN @Travel_Sum TS 
      ON TR.State = TS.State 
    WHERE RowNum = 1 
    UNION ALL 
    SELECT 
     R2.ID, 
     R2.State, 
     R2.Days_Count, 
     R2.RowNum, 
     R1.Exceeding_Amt - R2.Days_Count, 
     CASE WHEN R1.Exceeding_Amt > R2.Days_Count THEN R2.Days_Count ELSE R1.Exceeding_Amt END AS Remaining_days 
    FROM CTE R1 
     INNER JOIN TravelRows R2 
      ON R1.State = R2.State 
       AND R1.RowNum + 1 = R2.RowNum 
) 
    SELECT 
     ID, 
     State, 
     Days_Count, 
     Remaining_Days 
    FROM CTE 
    OPTION (MAXRECURSION 0) 

Выход:

ID   State  Days_Count Remaining_Days 
----------- ---------- ----------- -------------- 
1   AL   20   20 
2   AL   2   2 
3   AL   14   2 
+0

Спасибо за ответ. Это выглядит довольно сложно. Я попробую. – Kartic

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