简体   繁体   English

使用日期和储罐名称的递归 T-SQL 查询

[英]Recursive T-SQL query Using Dates and Tank names

Ok, here's the story: I work for a company that recycles hazardous liquid chemicals into useful chemicals.好的,故事是这样的:我在一家将危险液体化学品回收成有用化学品的公司工作。 Part of this process involves moving these materials from one tank to another as each part of the recycling process is complete.此过程的一部分涉及将这些材料从一个罐转移到另一个罐,因为回收过程的每个部分都已完成。 These tanks are either in our tank farm, part of the distillation system, in rail cars, or tanker trucks.这些罐位于我们的罐区、蒸馏系统的一部分、轨道车或油罐车中。 The task I was assigned was to write a query that will allow the manager to pick up with any tank and follow the movement of that material through every tank until it is disposed of or sold.我被分配的任务是编写一个查询,让经理可以拿起任何罐,并跟踪该材料在每个罐中的移动,直到它被处理或出售。 The database was built some 10 years ago, before my time, so the data is all I have to work with (ie can't change it to make it easier to work with).该数据库是在大约 10 年前建立的,比我还早,所以我只需要使用数据(即无法更改它以使其更易于使用)。

Now the table structure: the columns that lend themselves to this endeavor are:现在的表结构:适合这项工作的列是:

  • SouceTank汤罐
  • OpenDate (The day the empty tank starts receiving material) OpenDate(空罐开始接收材料的日期)
  • CosedDate (The date the tank is closed, emptied, and made ready for new material) CosedDate(储罐关闭、清空并准备好接受新材料的日期)
  • DestinationTank (The tank the material was moved to) DestinationTank(材料被移动到的罐)
  • ProductName (I add this to validate movements. Many materials can't be mixed. Some are. The ones that can't be mixed could show a problem if the algorithm is not working correctly.) ProductName(我添加这个来验证动作。许多材料不能混合。有些是。如果算法不能正常工作,那些不能混合的可能会出现问题。)

All tanks will have an OpenDate but tanks still being filled or waiting to be shipped out would not have a closed date.所有储罐都有一个开放日期,但仍在填充或等待运出的储罐没有关闭日期。 Mostly, tanks are chemical agnostic -as in, any empty tank can be used for any chemical.大多数情况下,储罐是化学不可知的——例如,任何空储罐都可以用于任何化学品。 Anywhere from 1 to 10 movements can be expected.任何地方都可以预期 1 到 10 次移动。

I tried using a recursive CTE T-SQL algorithm but quickly got lost trying to match the SourceTank to the matching DestinationTank where the CosedDate of the SourceTank was between the OpenDate and CosedDate of the DestinationTank, or at least after or equal to the OpenDate of the DestinationTank if it has yet to be closed.我尝试使用递归 CTE T-SQL 算法,但在尝试将 SourceTank 与匹配的 DestinationTank 匹配时很快就迷路了,其中 SourceTank 的 CosedDate 介于 DestinationTank 的 OpenDate 和 CosedDate 之间,或者至少在或等于如果 DestinationTank 尚未关闭。

Sample data:样本数据:

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  

Here's what I tried.这是我尝试过的。 Didn't know how to handle the NULL ClosingDate..不知道如何处理 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)

I'm not sure how useful this will be as I don't know what the expected result should look like, but it might assist.我不确定这会有多大用处,因为我不知道预期的结果应该是什么样子,但它可能会有所帮助。 I was trying to make sense of the dates so that's why you will see them concatenated into a pathway columns.我试图理解日期,这就是为什么你会看到它们连接成一个路径列。 I also wasn't sure where to start so I guessed at the earliest startdate for each tank.我也不知道从哪里开始,所以我猜测每个坦克的最早开始日期。

SQL Fiddle SQL小提琴

MS SQL Server 2014 Schema Setup : 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')
;

Query 1 :查询 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 |

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM