根据特定数量运行总值记录批处理(FileSize明智批处理)

时间:2017-09-20 12:48:12

标签: sql sql-server

我们正在处理大型记录集,并且当前正在使用NTILE()来获取FileID的范围,然后使用BETWEEN子句中的FileID列来获取特定的记录集。在BETWEEN子句中使用FileID是开发人员的强制要求。因此,我们不能在一个批处理中使用随机FileID,它必须是增量的。

根据新要求,我们必须根据FileSize列制作范围,例如:每批100 GB。

例如:

Batch 1 : 1 has 100 size So ID: 1 record only.
Batch 2 : 2,3,4,5 = 80 but it is < 100 GB, so have to take FileId 6 if 120 GB (Total 300 GB) 
Batch 3 : 7 ID has > 100 so 1 record only
And so on…

以下是我的示例代码,但未提供预期结果:

CREATE TABLE zFiles
(
    FileId   INT
   ,FileSize INT
)

INSERT INTO dbo.zFiles (
                           FileId
                          ,FileSize
                       )
VALUES (1, 100)
      ,(2, 20)
      ,(3, 20)
      ,(4, 30)
      ,(5, 10)
      ,(6, 120)
      ,(7, 400)
      ,(8, 50)
      ,(9, 100)
      ,(10, 60)
      ,(11, 40)
      ,(12, 5)
      ,(13, 20)
      ,(14, 95)
      ,(15, 40) 

DECLARE @intBatchSize FLOAT = 100;
SELECT   y.FileID ,
         y.FileSize ,
         y.RunningTotal ,
         DENSE_RANK() OVER (ORDER BY CEILING(RunningTotal / @intBatchSize)) Batch
FROM     (   SELECT i.FileID ,
                    i.FileSize ,
                    RunningTotal = SUM(i.FileSize) OVER ( ORDER BY i.FileID ) -- RANGE UNBOUNDED PRECEDING)
             FROM   dbo.zFiles AS i WITH ( NOLOCK )
         ) y
ORDER BY y.FileID;

结果:

+--------+----------+--------------+-------+
| FileID | FileSize | RunningTotal | Batch |
+--------+----------+--------------+-------+
|      1 |      100 |          100 |     1 |
|      2 |       20 |          120 |     2 |
|      3 |       20 |          140 |     2 |
|      4 |       30 |          170 |     2 |
|      5 |       10 |          180 |     2 |
|      6 |      120 |          300 |     3 |
|      7 |      400 |          700 |     4 |
|      8 |       50 |          750 |     5 |
|      9 |      100 |          850 |     6 |
|     10 |       60 |          910 |     7 |
|     11 |       40 |          950 |     7 |
|     12 |        5 |          955 |     7 |
|     13 |       20 |          975 |     7 |
|     14 |       95 |         1070 |     8 |
|     15 |       40 |         1110 |     9 |
+--------+----------+--------------+-------+

预期结果:

+--------+---------------+---------+
| FileID | FileSize (GB) | BatchNo |
+--------+---------------+---------+
|      1 |           100 |       1 |
|      2 |            20 |       2 |
|      3 |            20 |       2 |
|      4 |            30 |       2 |
|      5 |            10 |       2 |
|      6 |           120 |       2 |
|      7 |           400 |       3 |
|      8 |            50 |       4 |
|      9 |           100 |       4 |
|     10 |            60 |       5 |
|     11 |            40 |       5 |
|     12 |             5 |       6 |
|     13 |            20 |       6 |
|     14 |            95 |       6 |
|     15 |            40 |       7 |
+--------+---------------+---------+

我们可以实现这个,如果我们可以在它超过100时重置运行总数。我们可以编写一个循环来获得这个结果,但为此我们需要按记录记录,这很费时。

请有人帮助我们吗?

2 个答案:

答案 0 :(得分:1)

您需要使用递归CTE执行此操作:

with cte as (
      select z.fileid, z.filesize, z.filesize as batch_filesize, 1 as batchnum
      from zfiles z
      where z.fileid = 1
      union all
      select z.fileid, z.filesize,
             (case when cte.batch_filesize + z.filesize > @intBatchSize
                   then z.filesize
                   else cte.batch_filesize + z.filesize
              end),
             (case when cte.batch_filesize + z.filesize > @intBatchSize
                   then cte.batchnum + 1
                   else cte.batchnum
              end)
      from cte join
           zfiles z
           on z.fileid = cte.fileid + 1
     )
select *
from cte;

注意:我意识到fileid可能不是一个序列。您可以在CTE中使用row_number()创建序列,以使其工作。

有一个技术原因,为什么运行总和不适用于此。基本上,任何给定的fileid都需要知道它之前的中断。

答案 1 :(得分:0)

戈登·林诺夫(Gordon Linoff)对上述答案进行了小幅修改,得到了预期的结果。

&#13;
&#13;
DECLARE @intBatchSize INT = 100
;WITH cte as (
      select z.fileid, z.filesize, z.filesize as batch_filesize, 1 as batchnum
      from zfiles z
      where z.fileid = 1
      union all
      select z.fileid, z.filesize,
             (case when cte.batch_filesize  >= @intBatchSize
                   then z.filesize
                   else cte.batch_filesize + z.filesize
              end),
             (case when cte.batch_filesize  >= @intBatchSize
                   then cte.batchnum + 1
                   else cte.batchnum
              end)
      from cte join
           zfiles z
           on z.fileid = cte.fileid + 1
     )
select *
from cte;
&#13;
&#13;
&#13;