递归T-SQL查询使用日期和坦克名称

时间:2017-10-11 22:59:43

标签: sql sql-server tsql sql-server-2008-r2 common-table-expression

好的,这就是故事:我在一家公司工作,将危险的液体化学品回收成有用的化学品。该过程的一部分涉及在回收过程的每个部分完成时将这些材料从一个罐移动到另一个罐。这些罐位于我们的罐区,蒸馏系统的一部分,铁路车辆或油罐车中。我被分配的任务是写一个查询,允许经理拿起任何油箱,并跟踪每个油箱的物料移动,直到它被处置或出售。数据库是在大约10年前,在我的时间之前建立的,所以数据是我必须处理的(即不能改变它以使其更容易使用)。

现在表格结构:适合这项努力的专栏是:

  • SouceTank
  • OpenDate(空罐开始接收材料的那一天)
  • CosedDate(坦克关闭,清空并为新材料做好准备的日期)
  • DestinationTank(材料移动到的水箱)
  • ProductName(我添加它来验证移动。许多材料不能混合。有些是。如果算法不能正常工作,那些无法混合的材料可能会出现问题。)

所有坦克都将有一个OpenDate,但坦克仍在装满或等待运出,因此没有关闭日期。大多数情况下,坦克是化学不可知的 - 在任何情况下,任何空罐都可用于任何化学品。可以预期从1到10次移动。

我尝试使用递归CTE T-SQL算法,但很快就试图将SourceTank与匹配的DestinationTank匹配,其中SourceTank的CosedDate位于DestinationTank的OpenDate和CosedDate之间,或者至少等于或等于如果还没有关闭,那么DestinationTank的OpenDate。

示例数据:

SourceTank  StartDate    ClosedDate   DestinationTank   ProductName  
------------------------------------------------------------------------
TNK01-5     08/03/2017   08/10/2017   TNK30-6           Fuels  
TNK01-5     08/07/2017   08/10/2017   TNK40-6           Fuels  
TNK01-5     07/20/2017   07/31/2017   TNK01-5           Incin  
TNK01-5     08/10/2017   08/17/2017   TNK30-6           Incin  
TNK01-5     08/12/2017   08/17/2017   TNK30-6           Fuels  
TNK03-5     08/13/2017   08/22/2017   TNK30-6           IBAC feed  
TNK07-5     08/11/2017   08/17/2017   TNK40-6           Incin  
TNK07-5     08/14/2017   08/29/2017   TNK40-6           Fuels  
TNK07-5     07/15/2017   08/10/2017   TNK30-6           Picoline Cut  
TNK07-5     08/03/2017   08/10/2017   TNK02-5           Pico 2nd Pass  
TNK07-5     08/06/2017   08/17/2017   TNK40-6           Fuels  
TNK08-5     08/05/2017   08/10/2017   TNK40-6           Fuels  
TNK08-5     08/07/2017   08/08/2017   TNK30-6           Fuels  
TNK08-5     08/10/2017   08/22/2017   TNK40-6           Water  
TNK08-5     07/24/2017   08/10/2017   TNK02-5           Picoline Cut  
TNK09-10    07/20/2017   NULL         TNK30-6           Picoline Crude  
TNK09-10    07/21/2017   08/04/2017   TNK30-6           Picoline Crude  
TNK09-10    08/02/2017   08/10/2017   TNK30-6           Cyclo Waste  
TNK09-10    08/05/2017   08/10/2017   TNK30-6           Cyclo Waste  
TNK09-10    08/07/2017   08/10/2017   TNK30-6           Cyclo Waste  
TNK09-10    08/04/2017   08/10/2017   TNK30-6           Cyclo Waste  
TNK09-10    08/15/2017   08/22/2017   TNK30-6           IBAC feed  
TNK09-10    08/11/2017   08/17/2017   TNK30-6           IBAC feed  
TNK09-10    08/12/2017   08/17/2017   TNK30-6           IBAC feed  
TNK30-6     08/08/2017   08/29/2017   TNK30-6           Cyclo Waste  
TNK40-6     08/13/2017   08/22/2017   TNK30-6           IBAC:PRODUCT  
TNK41-6     08/14/2017   09/27/2017   NATX25496         IBAC:PRODUCT  
TNK51-12    07/26/2017   09/15/2017   TNK30-6           CYCLO Product  
TNK62-12    07/28/2017   09/12/2017   TNK30-6           NON-RCRA NMP  
TNK74-12    07/29/2017   NULL         TNK30-6           Picoline Crude  
TNK91-8     08/03/2017   08/22/2017   TNK08-5           Picoline Prod  

这是我尝试过的。我不知道如何处理NULL ClosingDate ..

WITH TanksCTE AS (
SELECT [TrackingNum]
      ,[TblTankTracking].[TankID]
      ,[StartDate]
      ,[TblTankTracking].[ProductID]
      ,[ClosedDate]
      ,[Destination]
  FROM [MAFTS].[Laboratory].[TblTankTracking]

UNION ALL  

SELECT TCTE.[TrackingNum]
      ,TRACK.[TankID]
      ,TRACK.[StartDate]
      ,TRACK.[ProductID]
      ,TRACK.[ClosedDate]
      ,TRACK.[Destination]
  FROM TanksCTE AS TCTE INNER JOIN 
       [MAFTS].[Laboratory].[TblTankTracking]  TRACK
       ON  TCTE.[TankID] = TRACK.[Destination] 
       AND TRACK.[ClosedDate] BETWEEN  TCTE.[StartDate] AND TCTE.[ClosedDate]
)

SELECT * FROM TanksCTE
    option (maxrecursion 0)

1 个答案:

答案 0 :(得分:1)

我不确定这会有多大用处,因为我不知道预期的结果应该是什么样的,但它可能有所帮助。我试图理解日期,这就是为什么你会看到它们连接成一个路径列。我也不确定从哪里开始,所以我猜到每个坦克最早的开始日期。

SQL Fiddle

MS SQL Server 2014架构设置

CREATE TABLE Table1
    ([SourceTank] varchar(8), [StartDate] datetime, [ClosedDate] datetime, [DestinationTank] varchar(9), [ProductName] varchar(14))
;

INSERT INTO Table1
    ([SourceTank], [StartDate], [ClosedDate], [DestinationTank], [ProductName])
VALUES
    ('TNK01-5', '2017-08-03 00:00:00', '08/10/2017', 'TNK30-6', 'Fuels'),
    ('TNK01-5', '2017-08-07 00:00:00', '08/10/2017', 'TNK40-6', 'Fuels'),
    ('TNK01-5', '2017-07-20 00:00:00', '07/31/2017', 'TNK01-5', 'Incin'),
    ('TNK01-5', '2017-08-10 00:00:00', '08/17/2017', 'TNK30-6', 'Incin'),
    ('TNK01-5', '2017-08-12 00:00:00', '08/17/2017', 'TNK30-6', 'Fuels'),
    ('TNK03-5', '2017-08-13 00:00:00', '08/22/2017', 'TNK30-6', 'IBAC feed'),
    ('TNK07-5', '2017-08-11 00:00:00', '08/17/2017', 'TNK40-6', 'Incin'),
    ('TNK07-5', '2017-08-14 00:00:00', '08/29/2017', 'TNK40-6', 'Fuels'),
    ('TNK07-5', '2017-07-15 00:00:00', '08/10/2017', 'TNK30-6', 'Picoline Cut'),
    ('TNK07-5', '2017-08-03 00:00:00', '08/10/2017', 'TNK02-5', 'Pico 2nd Pass'),
    ('TNK07-5', '2017-08-06 00:00:00', '08/17/2017', 'TNK40-6', 'Fuels'),
    ('TNK08-5', '2017-08-05 00:00:00', '08/10/2017', 'TNK40-6', 'Fuels'),
    ('TNK08-5', '2017-08-07 00:00:00', '08/08/2017', 'TNK30-6', 'Fuels'),
    ('TNK08-5', '2017-08-10 00:00:00', '08/22/2017', 'TNK40-6', 'Water'),
    ('TNK08-5', '2017-07-24 00:00:00', '08/10/2017', 'TNK02-5', 'Picoline Cut'),
    ('TNK09-10', '2017-07-20 00:00:00', NULL, 'TNK30-6', 'Picoline Crude'),
    ('TNK09-10', '2017-07-21 00:00:00', '08/04/2017', 'TNK30-6', 'Picoline Crude'),
    ('TNK09-10', '2017-08-02 00:00:00', '08/10/2017', 'TNK30-6', 'Cyclo Waste'),
    ('TNK09-10', '2017-08-05 00:00:00', '08/10/2017', 'TNK30-6', 'Cyclo Waste'),
    ('TNK09-10', '2017-08-07 00:00:00', '08/10/2017', 'TNK30-6', 'Cyclo Waste'),
    ('TNK09-10', '2017-08-04 00:00:00', '08/10/2017', 'TNK30-6', 'Cyclo Waste'),
    ('TNK09-10', '2017-08-15 00:00:00', '08/22/2017', 'TNK30-6', 'IBAC feed'),
    ('TNK09-10', '2017-08-11 00:00:00', '08/17/2017', 'TNK30-6', 'IBAC feed'),
    ('TNK09-10', '2017-08-12 00:00:00', '08/17/2017', 'TNK30-6', 'IBAC feed'),
    ('TNK30-6', '2017-08-08 00:00:00', '08/29/2017', 'TNK30-6', 'Cyclo Waste'),
    ('TNK40-6', '2017-08-13 00:00:00', '08/22/2017', 'TNK30-6', 'IBAC:PRODUCT'),
    ('TNK41-6', '2017-08-14 00:00:00', '09/27/2017', 'NATX25496', 'IBAC:PRODUCT'),
    ('TNK51-12', '2017-07-26 00:00:00', '09/15/2017', 'TNK30-6', 'CYCLO Product'),
    ('TNK62-12', '2017-07-28 00:00:00', '09/12/2017', 'TNK30-6', 'NON-RCRA NMP'),
    ('TNK74-12', '2017-07-29 00:00:00', NULL, 'TNK30-6', 'Picoline Crude'),
    ('TNK91-8', '2017-08-03 00:00:00', '08/22/2017', 'TNK08-5', 'Picoline Prod')
;

查询1

with TankStart as (
    select 
           *
         , row_number() over(partition by SourceTank order by StartDate ASC) as rn
    from Table1
    )
, TankPaths as (
      SELECT
            T.SourceTank
          , T.DestinationTank
          , T.StartDate
          , T.ClosedDate
          , T.ProductName
          , CAST(T.DestinationTank AS varchar(max)) 
            + ' '  
            + convert(varchar(10),T.ClosedDate,120)
            AS Pathway
      FROM TankStart T
      WHERE T.rn = 1
      union all
      SELECT
            T1.SourceTank
          , T1.DestinationTank
          , T1.StartDate
          , T1.ClosedDate
          , T1.ProductName
          , M.Pathway 
            + ' '  
            + convert(varchar(10),T1.StartDate,120)
            + ', ' 
            + CAST(T1.DestinationTank AS varchar(max)) 
            + ', ' 
            + convert(varchar(10),T1.ClosedDate,120)

      FROM Table1 T1
      INNER JOIN TankPaths M ON M.DestinationTank = T1.SourceTank
                       AND M.ClosedDate <= T1.StartDate
      where T1.SourceTank <> T1.DestinationTank
    )
select * 
from TankPaths
order by 1, 2, Pathway

<强> Results

| SourceTank | DestinationTank |            StartDate |           ClosedDate |    ProductName |                                                                            Pathway |
|------------|-----------------|----------------------|----------------------|----------------|------------------------------------------------------------------------------------|
|    TNK01-5 |         TNK01-5 | 2017-07-20T00:00:00Z | 2017-07-31T00:00:00Z |          Incin |                                                                 TNK01-5 2017-07-31 |
|    TNK01-5 |         TNK30-6 | 2017-08-03T00:00:00Z | 2017-08-10T00:00:00Z |          Fuels |                                 TNK01-5 2017-07-31 2017-08-03, TNK30-6, 2017-08-10 |
|    TNK01-5 |         TNK30-6 | 2017-08-10T00:00:00Z | 2017-08-17T00:00:00Z |          Incin |                                 TNK01-5 2017-07-31 2017-08-10, TNK30-6, 2017-08-17 |
|    TNK01-5 |         TNK30-6 | 2017-08-12T00:00:00Z | 2017-08-17T00:00:00Z |          Fuels |                                 TNK01-5 2017-07-31 2017-08-12, TNK30-6, 2017-08-17 |
|    TNK01-5 |         TNK40-6 | 2017-08-07T00:00:00Z | 2017-08-10T00:00:00Z |          Fuels |                                 TNK01-5 2017-07-31 2017-08-07, TNK40-6, 2017-08-10 |
|    TNK03-5 |         TNK30-6 | 2017-08-13T00:00:00Z | 2017-08-22T00:00:00Z |      IBAC feed |                                                                 TNK30-6 2017-08-22 |
|    TNK07-5 |         TNK30-6 | 2017-07-15T00:00:00Z | 2017-08-10T00:00:00Z |   Picoline Cut |                                                                 TNK30-6 2017-08-10 |
|    TNK08-5 |         TNK02-5 | 2017-07-24T00:00:00Z | 2017-08-10T00:00:00Z |   Picoline Cut |                                                                 TNK02-5 2017-08-10 |
|   TNK09-10 |         TNK30-6 | 2017-07-20T00:00:00Z |               (null) | Picoline Crude |                                                                             (null) |
|    TNK30-6 |         TNK30-6 | 2017-08-08T00:00:00Z | 2017-08-29T00:00:00Z |    Cyclo Waste |                                                                 TNK30-6 2017-08-29 |
|    TNK40-6 |         TNK30-6 | 2017-08-13T00:00:00Z | 2017-08-22T00:00:00Z |   IBAC:PRODUCT | TNK01-5 2017-07-31 2017-08-07, TNK40-6, 2017-08-10 2017-08-13, TNK30-6, 2017-08-22 |
|    TNK40-6 |         TNK30-6 | 2017-08-13T00:00:00Z | 2017-08-22T00:00:00Z |   IBAC:PRODUCT |                                                                 TNK30-6 2017-08-22 |
|    TNK41-6 |       NATX25496 | 2017-08-14T00:00:00Z | 2017-09-27T00:00:00Z |   IBAC:PRODUCT |                                                               NATX25496 2017-09-27 |
|   TNK51-12 |         TNK30-6 | 2017-07-26T00:00:00Z | 2017-09-15T00:00:00Z |  CYCLO Product |                                                                 TNK30-6 2017-09-15 |
|   TNK62-12 |         TNK30-6 | 2017-07-28T00:00:00Z | 2017-09-12T00:00:00Z |   NON-RCRA NMP |                                                                 TNK30-6 2017-09-12 |
|   TNK74-12 |         TNK30-6 | 2017-07-29T00:00:00Z |               (null) | Picoline Crude |                                                                             (null) |
|    TNK91-8 |         TNK08-5 | 2017-08-03T00:00:00Z | 2017-08-22T00:00:00Z |  Picoline Prod |                                                                 TNK08-5 2017-08-22 |