如何使用数字表进行扩展 - 爆炸内存和硬盘

时间:2015-10-25 14:03:37

标签: sql sql-server sql-server-2008 tsql sql-server-2014

我正在尝试使用某些日期的某些值填充半满的列,其余日期为NULL。

  • 该任务基本填补了前一行值的空白。 它需要n次迭代才能填满整个表格。 我正在使用NUMBERS表进行迭代,它适用于小样本表,如下所示。

  • 当完成18行行数据时,它无法完成查询,因为它会爆炸计算机资源并且运行时无穷无尽。如何扩大规模?

还是有更好的方法吗?这个解决方案起初对我来说似乎很好。

'原样'并且[statusTEST]列如下:

╔════════════╦═══════════╦════════════╦═════════════════╦═════════════════╗
║ SOZLESMENO ║ tDuration ║  YRMONTH   ║ statusTest_AsIs ║ statusTest_ToBE ║
╠════════════╬═══════════╬════════════╬═════════════════╬═════════════════╣
║   40000001 ║         0 ║ 2010-01-01 ║ 1               ║               1 ║
║   40000001 ║         1 ║ 2010-02-01 ║ NULL            ║               1 ║
║   40000001 ║         2 ║ 2010-03-01 ║ NULL            ║               1 ║
║   40000001 ║         3 ║ 2010-04-01 ║ NULL            ║               1 ║
║   40000001 ║         4 ║ 2010-05-01 ║ 2               ║               2 ║
║   40000001 ║         5 ║ 2010-06-01 ║ NULL            ║               2 ║
║   40000001 ║         6 ║ 2010-07-01 ║ NULL            ║               2 ║
║   40000001 ║         7 ║ 2010-08-01 ║ NULL            ║               2 ║
║   40000001 ║         8 ║ 2010-09-01 ║ 3               ║               3 ║
║   40000001 ║         9 ║ 2010-10-01 ║ NULL            ║               3 ║
║   40000001 ║        10 ║ 2010-11-01 ║ NULL            ║               3 ║
╚════════════╩═══════════╩════════════╩═════════════════╩═════════════════╝

我使用以下代码和预定义的10,000行数表

--Numbers table defined
SELECT TOP 10000 H = IDENTITY(INT, 0, 1)
INTO dbo.Numbers
FROM master.dbo.syscolumns a
CROSS JOIN master.dbo.syscolumns b;

--Alternating the table H times to get statusTest_toBE column shown above
DECLARE @iteration_limit INT = 60

UPDATE X
SET X.statusTest = (
        CASE 
            WHEN X.statusTest IS NOT NULL THEN X.statusTest
            ELSE Y.statusTest
        END
        )
FROM 
           [Mainfiles].dbo.x2Skeleton X 
CROSS JOIN [Mainfiles].dbo.Numbers3 N
LEFT JOIN  [Mainfiles].dbo.x2Skeleton Y 
       ON (X.SOZLESMENO = Y.SOZLESMENO)
      AND (DATEADD(MONTH, - N.H, X.YRMONTH) = Y.YRMONTH)
      AND N.H BETWEEN 1 AND @iteration_limit

1 个答案:

答案 0 :(得分:3)

您可以使用窗口功能表达您想要的内容。如果StatusTest_AsIs总是在增加,您可以使用max()

with toupdate as (
      select X.*, max(StatusTest_AsIs) over (partition by SOZLESMENO order by YRMONTH) as new_statusTest_ToBE
      from [Mainfiles].dbo.x2Skeleton X
     )
update toupdate
    set statusTest_ToBE = new_statusTest_ToBE
    where statusTest_ToBE <> new_statusTest_ToBE;

如果值没有增加,您仍然可以执行此操作。获取先前的非NULL值有点棘手,但APPLY是一种很好的方法:

with toupdate as (
      select X.*, x2.StatusTest_AsIs as new_statusTest_ToBE
      from [Mainfiles].dbo.x2Skeleton x cross apply
           (select top 1
            from  [Mainfiles].dbo.x2Skeleton x2
            where x2.SOZLESMENO = x.SOZLESMENO and x2.YRMONTH <= YRMONTH and
                  x2.StatusTest_AsIs is not null
            order by YRMONTH desc
           ) x2
     )
update toupdate
    set statusTest_ToBE = new_statusTest_ToBE
    where statusTest_ToBE <> new_statusTest_ToBE;

对于这两个查询,特别是这个查询,您需要[Mainfiles].dbo.x2Skeleton(SOZLESMENO, YRMONTH, StatusTest_AsIs)上的索引。