MSSQL查找创建者批处理 - 没有游标

时间:2018-02-28 10:20:50

标签: sql-server rbar

我正在寻找SQL2016上的以下帮助

我有批次需要识别父批次。

我需要填写的是ParentBatchID,并且应该按照这个逻辑工作:

  1. 如果存在先前批次,其中当前批次的起始日期是在上一批次的从和之间 - >>那是parrent
  2. 如果识别出的parrentBatchID为0,则获取parrent的BatchID,如果它不是0,则获取parrentBatchID(继承它)
  3. 到目前为止,我用光标做了这个,但是你知道RBAR的性能。 *当当前fromDate介于之前和之后+ 1之后是isnull(parrentBatchID,batchid)*

    我尝试使用窗口函数,但由于我需要继承的parrentID在下一行中不存在,我失败了,只是到处都是0-s :(

    我对数据进行了自由操作,并尝试了各种准备方法。

    Create table myTest (BatchID int, Product int, LenghtDay int, fromDate datetime, toDate Datetime, ParentBatchID int);
    
    insert into myTest VALUES (1,1,9,'2000-01-01 00:00:00','2000-01-10 00:00:00',null);
    insert into myTest VALUES (2,1,4,'2000-01-08 00:00:00','2000-01-12 00:00:00',null);
    insert into myTest VALUES (3,1,5,'2000-01-13 00:00:00','2000-01-18 00:00:00',null);
    insert into myTest VALUES (4,1,2,'2000-01-20 00:00:00','2000-01-22 00:00:00',null);
    insert into myTest VALUES (5,2,7,'2000-01-21 00:00:00','2000-01-28 00:00:00',null);
    

    预期输出

    BatchID,ProductID,ParentBatchID 
    1,1,0
    2,1,1 --as it's from (01.08) is between #1's from (01.01) and to+1 (01.11)
    3,1,1 --as it's from (01.13) is between #2's from (01.08) and to+1 (01.13), so it needs to inherit #2's parent batch ID: 1
    4,1,0 --as it's not between #3's from and to, it's a new batch
    5,2,0 --as it's a different product, different batch
    

    ---------- 有一个扩展的问题版本,如果我识别parrent我需要延长它的长度与孩子的长度一天,我需要检查下一个孩子,如果它来自来自 - >到+之前的孩子们的长度。 坦率地说,我不知道如何实现这一点。 ---------- 扩展版本 - 第4行将是不同的

    BatchID,ProductID,ParentBatchID 
    1,1,0
    2,1,1 --as it's from (01.08) is between #1's from (01.01) and to+1 (01.11)
    3,1,1 --as it's from (01.13) is between #1's from (01.01) and to+1+#2's length (01.10+1+4=016), so it needs to inherit #2's parent batch ID: 1
    4,1,1 --! ParentBatchID=1 ! as it's from (01.20) is between the from (01.01) and to+1+extended by all previous children's length (01.10+1+4+5=01.20), so it needs to inherit #3's parent batch ID: 1  
    5,2,0 --as it's a different product, different batch
    

    欢迎所有指导和帮助 提前谢谢

    尼克洛

    修改

    递归解决方案很棒,但只适用于最有限的数据集。你能建议一种更具伸缩性的方法吗?

    谢谢

1 个答案:

答案 0 :(得分:0)

import numpy as np

mas1 = np.array([[True, False,  True],
       [ False,  True,  True],
       [ False,  True,  False]])

mas_answer = np.ndarray(shape=mas1.shape)

for i in range(mas1.shape[0]):
    for j in range(mas1.shape[1]):
        close_elt = []
        if i >= 1:
            try:
                close_elt.append(mas1[i-1,j])
            except:
                pass
            try:
                close_elt.append(mas1[i-1,j+1])
            except:
                pass

        if j >= 1:
            try:
                close_elt.append(mas1[i+1,j-1])
            except:
                pass
            try:
                close_elt.append(mas1[i,j-1])
            except:
                pass

        if i >= 1 and j >= 1:
            try:
                close_elt.append(mas1[i-1,j-1])
            except:
                pass

        try:
            close_elt.append(mas1[i,j+1])
        except:
            pass

        try:
            close_elt.append(mas1[i+1,j])
        except:
            pass
        try:
            close_elt.append(mas1[i+1,j+1])
        except:
            pass

        mas_answer[i,j] = close_elt.count(True)


# Ouput:
mas_answer
Out[27]: 
array([[1., 4., 2.],
       [3., 4., 3.],
       [2., 2., 3.]])

http://sqlfiddle.com/#!18/971f3/37

;with t as 
(
  select tt.BatchID, tt.Product, tt.fromDate, tt.toDate, 0 ParentBatchID, 1 lvl, tt.BatchID rootID
  from myTest tt
  where not exists(select 1 from myTest t 
                   where t.Product=tt.Product 
                     and tt.BatchID <> t.BatchID
                     and tt.fromDate between t.fromDate and dateadd(day, 1, t.toDate)
                  )

  union all

  select tt.BatchID, tt.Product, tt.fromDate, tt.toDate, t.BatchID, t.lvl+1, t.rootID
  from t
  INNER JOIN myTest tt
  on tt.Product = t.Product
  where tt.BatchID <> t.BatchID 
    and tt.fromDate between t.fromDate and dateadd(day, 1, t.toDate)
)
select BatchId, Product, ParentBatchID, rootId, lvl
from t
order by Product, fromDate, lvl