2012-03-02 4 views
2

У меня есть таблица с этими столбцамиавтообъединения Обновления строк таблицы

- ProjectId 
- Generation 
- Expected 
- CarryOver 

Я пытаюсь обновить уже заселенную таблицу таким образом:

Generation = Integral Part of ((Generation + CarryOver of Previous Row)/10) 
    CarryOver = decimal part of ((Generation + CarryOver of Previous Row)/10) 

где Предыдущая строка и текущие Роу оба имеют такой же ProjectID

Ниже запрос я использую для достижения этого:

UPDATE TTable 

SET 

TTable.Expected=(TTable.Generation+ ISNULL(STable.CarryOver,0)), 
TTable.CarryOver =(TTable.Generation+ISNULL(STable.CarryOver,0))-CONVERT(INT,(TTable.Generation+ISNULL(STable.CarryOver,0))) 

FROM 
(
    SELECT ROW_NUMBER()OVER(order by ProjectId,MonthYear) as RowNumber,ProjectId, 
    [MonthYear],[Month],[Generation],[Expected],[CarryOver] 
    FROM #SRECEsimated 
)TTable, 

(
    SELECT ROW_NUMBER()OVER(order by ProjectId,MonthYear) as RowNumber,ProjectId, 
     [MonthYear],[Month],[Generation],[Expected],[CarryOver] 
    FROM #SRECEsimated 
) STable 


Where 
TTable.RowNumber = STable.RowNumber+1 AND 
TTable.ProjectId = STable.ProjectId 

.... но что-то странное происходит, обновление происходит только для первых двух строк. Для других строк ISNULL(STable.CarryOver,0) возвращает 0. why ?? Пожалуйста, помогите мне. или предложить другой способ для достижения этой

EDIT: на выполнение запроса генерируется

ProjectId MonthYear Month Year Generation Expected CarryOver 
10 2011-10-01 00:00:00.000 10 2011 56.748    56   0.748 
10 2011-11-01 00:00:00.000 11 2011 12.004    12   0.752 
10 2011-12-01 00:00:00.000 12 2011 10.632    10   0.632 
10 2012-01-01 00:00:00.000 01 2012 11.928    11   0.928 
10 2012-02-01 00:00:00.000 02 2012 7.580    7   0.580 
100 2011-12-01 00:00:00.000 12 2011 5.897    5   0.897 
100 2012-01-01 00:00:00.000 01 2012 0.881    1   0.778 

данных, как показано выше. обратите внимание на то, как логика не работает после 3row

Оригинальный вырез. Перед выполнением запроса на обновление:

ProjectId MonthYear Month Year Generation Expected CarryOver 
10 2011-10-01 00:00:00.000 10 2011 56.748   56    0.748 
10 2011-11-01 00:00:00.000 11 2011 12.004   NULL   NULL 
10 2011-12-01 00:00:00.000 12 2011 10.632   NULL   NULL 
10 2012-01-01 00:00:00.000 01 2012 11.928   NULL   NULL 
10 2012-02-01 00:00:00.000 02 2012 7.580    NULL   NULL 
100 2011-12-01 00:00:00.000 12 2011 5.897    5   0.897 
100 2012-01-01 00:00:00.000 01 2012 0.881    NULL   NULL 
+0

Что такое #SRECEstimated? – Hogan

+0

загляните в него –

+0

Рабочее решение опубликовано. – Hogan

ответ

0

Следующий запрос даст вам ожидаемые результаты

(Test код https://gist.github.com/1969171 для тех, кто хочет играть)

PID Date  M Y Generation Expected CarryOver 
10 2011-10-01 10 2011 56.748  56  0.748 
10 2011-11-01 11 2011 12.004  12  0.752 
10 2011-12-01 12 2011 10.632  11  0.384 
10 2012-01-01 01 2012 11.928  12  0.312 
10 2012-02-01 02 2012 7.58  7  0.892 
100 2011-12-01 12 2011 5.897  5  0.897 
100 2012-01-01 01 2012 0.881  1  0.778 

DECLARE rowItems CURSOR FOR 
SELECT ProjectId, [Month], [Year], Generation FROM TTable 
ORDER BY ProjectId,[Year] ,CAST([Month] as int) 

DECLARE @p int, @m VARCHAR(5), @y int, @g FLOAT, @priorP int, 
     @carryOver FLOAT, @expected FLOAT 

OPEN rowItems 

FETCH NEXT FROM rowItems INTO @p, @m, @y, @g 

SET @priorP = -1 
SET @carryOver = 0.0 

WHILE @@FETCH_STATUS = 0 
BEGIN 

    IF NOT @p = @priorP SET @carryOver = 0.0 

    SET @expected = @[email protected] 
    SET @carryOver = ROUND(@expected-FLOOR(@expected),3,0) 

    UPDATE TTable 
    SET EXPECTED = FLOOR(@expected), CarryOver = @carryOver 
    WHERE ProjectId = @p and [Month] = @m and [Year] = @y 

    SET @priorP = @p 

    FETCH NEXT FROM rowItems INTO @p, @m, @y, @g 

END 

CLOSE rowItems 
DEALLOCATE rowItems 

SELECT * FROM TTable 

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

+0

Я вижу, я мог бы улучшить это, используя поле datetime вместо столбцов месяца и года. Я оставлю это упражнение для читателя. – Hogan

+0

спасибо за ваш ответ hogan. Конечно, это работает, но курсоры. Я предполагаю, что уловка такова, что одно обновление по всей таблице не может этого сделать. для 500 записей в таблице должно быть выполнено 500 запросов на обновление (в цикле). –

+1

Я мог ошибаться ... но я не верю, что есть способ сделать это без курсоров или подзапроса, который имеет одинаковую производительность. Кроме того, я ожидаю, что это не вопрос, который вам нужно делать часто. Если это так, вы можете повторно спроектировать свой db, чтобы быстрее обрабатывать запрос. – Hogan

0

Извините за нарушение. Вот мое предложение.

Тестовые данные

CREATE TABLE TTable 
     (
      ProjectId INT, 
      MonthYear DATETIME, 
      Month VARCHAR(5), 
      Year INT, 
      Generation FLOAT, 
      Expected FLOAT, 
      CarryOver FLOAT 
     ) 
INSERT INTO TTable 
VALUES 
    (10,'2011-10-01 00:00:00.000','10',2011,56.748,56,0.748), 
    (10,'2011-11-01 00:00:00.000','11',2011,12.004,NULL,NULL), 
    (10,'2011-12-01 00:00:00.000','12',2011,10.632,NULL,NULL), 
    (10,'2012-01-01 00:00:00.000','01',2012,11.928,NULL,NULL), 
    (10,'2012-02-01 00:00:00.000','02',2012,7.580,NULL,NULL), 
    (100,'2011-12-01 00:00:00.000','12',2011,5.897,5,0.897), 
    (100,'2012-01-01 00:00:00.000','01',2012,0.881,NULL,NULL) 

Запрос

;WITH CTE 
AS 
(
    SELECT 
     ROW_NUMBER() OVER(ORDER BY tbl.ProjectId,tbl.Month) AS RowNbr, 
     tbl.ProjectId, 
     tbl.MonthYear, 
     tbl.Month, 
     tbl.Year, 
     tbl.Generation, 
     (
      FLOOR(tbl.Generation) 
     ) AS Expected, 
     (
      ROUND(tbl.Generation-FLOOR(tbl.Generation),3,0) 
     )AS CarryOver 
    FROM 
     TTable AS tbl 
) 
SELECT 
    CTE.ProjectId, 
    CTE.MonthYear, 
    CTE.Month, 
    CTE.Year, 
    CTE.Generation, 
    CTE.Expected, 
    (
     CTE.CarryOver+ISNULL(Previus.CarryOver,0) 
    ) AS CarryOver 
FROM 
    CTE 
    LEFT JOIN CTE AS Previus 
     ON CTE.RowNbr=Previus.RowNbr+1 

Результат

ProjectId MonthYear   Month Year Generation Expected CarryOver 
10 2011-10-01 00:00:00.000  10  2011 56,748  56   0,748 
10 2011-11-01 00:00:00.000  11  2011 12,004  12   0,752 
10 2011-12-01 00:00:00.000  12  2011 10,632  10   0,636 
10 2012-01-01 00:00:00.000  01  2012 11,928  11   1,56 
10 2012-02-01 00:00:00.000  02  2012 7,58  7   1,508 
100 2011-12-01 00:00:00.000  12  2011 5,897  5   1,477 
100 2012-01-01 00:00:00.000  01  2012 0,881  0   1,778 

Обновления запроса

;WITH CTE 
AS 
(
    SELECT 
     ROW_NUMBER() OVER(ORDER BY tbl.ProjectId,tbl.Month) AS RowNbr, 
     tbl.ProjectId, 
     tbl.MonthYear, 
     tbl.Month, 
     tbl.Year, 
     tbl.Generation, 
     (
      FLOOR(tbl.Generation) 
     ) AS Expected, 
     (
      ROUND(tbl.Generation-FLOOR(tbl.Generation),3,0) 
     )AS CarryOver 
    FROM 
     TTable AS tbl 
) 
UPDATE TTable 
SET TTable.CarryOver=CTE.CarryOver+ISNULL(Previus.CarryOver,0), 
    TTable.Expected=CTE.Expected 
FROM 
    (
     SELECT 
      ROW_NUMBER() OVER(ORDER BY TTable.ProjectId, 
             TTable.Month) AS RowNbr, 
      TTable.CarryOver, 
      TTable.Expected 
     FROM 
      TTable 
    ) AS TTable 
    JOIN CTE 
     ON TTable.RowNbr=CTE.RowNbr 
    LEFT JOIN CTE AS Previus 
     ON CTE.RowNbr=Previus.RowNbr+1 

Теперь при выборе для обновленной таблицы.Тогда вы получите этот результат:

ProjectId MonthYear   Month Year Generation Expected CarryOver 
10 2011-10-01 00:00:00.000  10  2011 56,748  56   0,748 
10 2011-11-01 00:00:00.000  11  2011 12,004  12   0,752 
10 2011-12-01 00:00:00.000  12  2011 10,632  10   0,636 
10 2012-01-01 00:00:00.000  01  2012 11,928  11   1,56 
10 2012-02-01 00:00:00.000  02  2012 7,58  7   1,508 
100 2011-12-01 00:00:00.000  12  2011 5,897  5   1,477 
100 2012-01-01 00:00:00.000  01  2012 0,881  0   1,778 
+0

Это неправильно. Например, 3-я строка должна иметь Expected = 11 (10.632 + .752 = 11.384) и переносить 0,384 – Hogan

0

Это, как я это сделал:

Для обновления первую запись, соответствующую каждому ProjectID:

Update TTable 

SET 

TTable.Expected=(TTable.Generation/10), 
TTable.CarryOver =(TTable.Generation/10)-CONVERT(INT,TTable.Generation/10) 


FROM 
(
     SELECT ROW_NUMBER()OVER(order by ProjectId,MonthYear) as RowNumber,ProjectId, 
     [MonthYear],[Month],[Generation],[Expected],[CarryOver] 
     FROM #SRECEsimated 
) TTable where TTable.RowNumber in 

(
    Select Min(TTable.RowNumber)as RowNumber From 
    ( 
     SELECT ROW_NUMBER()OVER(order by ProjectId,MonthYear) as RowNumber,ProjectId, 
     [MonthYear],[Month],[Generation],[Expected],[CarryOver] 
     FROM #SRECEsimated 
    ) as TTable GROUP by ProjectId 
) 

И для обновления остальных записей:

DECLARE @RowNumber INT = -99 
DECLARE @CarryOver decimal(4,3) =0 
DECLARE @Expected INT =0 
DECLARE @ProjectId int =0 
WHILE @RowNumber IS NOT NULL 
BEGIN 

     SET @RowNumber= (SELECT MIN(RowNumber) FROM (
           SELECT ROW_NUMBER()OVER(order by ProjectId,MonthYear) as RowNumber,ProjectId, 
           [MonthYear],[Month],[Generation],[Expected],[CarryOver] 
           FROM #SRECEsimated 
          ) as TTable 
         WHERE TTable.RowNumber> @RowNumber) 

     IF @RowNumber IS NULL 
     BREAK 

     SELECT @CarryOver= TTable.CarryOver,@ProjectId=TTable.ProjectId FROM 
          (
           SELECT ROW_NUMBER()OVER(order by ProjectId,MonthYear) as RowNumber,ProjectId, 
           [MonthYear],[Month],[Generation],[Expected],[CarryOver] 
           FROM #SRECEsimated   
          ) as TTable where TTable.RowNumber = @RowNumber 

     UPDATE TTable 
     SET TTable.Expected =([email protected])/10, 
     CarryOver = ([email protected])/10 - CONVERT(INT,([email protected])/10) 

     FROM     
     (
      SELECT ROW_NUMBER()OVER(order by ProjectId,MonthYear) as RowNumber,ProjectId, 
      [MonthYear],[Month],[Generation],[Expected],[CarryOver] 
      FROM #SRECEsimated   
     ) as TTable where TTable.RowNumber = @RowNumber+1 AND [email protected]    

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