在SQL Server中使用CTE查询进行递归匹配

Moo*_*ght 10 sql sql-server pattern-matching common-table-expression

我有两个表(它们在下面定义,您可以使用下面的SQL来构建它们)

IF EXISTS (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'ETab')
DROP TABLE ETab;
GO

CREATE TABLE ETab 
    ([MRN] varchar(20), [LSPEC] varchar(2), [ADT] DATETIME, [SDT] DATETIME, [Source] varchar(20), [Enum] varchar(20));
GO

INSERT INTO ETab ([MRN], [LSPEC], [ADT], [SDT], [Source], [Enum]) 
VALUES 
    ('HOMECARE',    'HM',       CONVERT(datetime, '2017-04-01 00:00:00.000', 20),   CONVERT(datetime, '2017-04-30 00:00:00.000', 20),   'PRODPAT',  'HOMEBLD04'),
    ('HOMECARE',    'HM',       CONVERT(datetime, '2017-05-01 00:00:00.000', 20),   CONVERT(datetime, '2017-05-31 00:00:00.000', 20),   'PRODPAT',  'HOMEBLD05'),
    ('HOMECARE',    'HM',       CONVERT(datetime, '2017-06-01 00:00:00.000', 20),   CONVERT(datetime, '2017-06-30 00:00:00.000', 20),   'PRODPAT',  'HOMEBLD06'),
    ('HOMECARE',    'HM',       CONVERT(datetime, '2017-07-01 00:00:00.000', 20),   CONVERT(datetime, '2017-07-31 00:00:00.000', 20),   'PRODPAT',  'HOMEBLD07'),
    ('HOMECARE',    'HM',       CONVERT(datetime, '2017-08-01 00:00:00.000', 20),   CONVERT(datetime, '2017-08-31 00:00:00.000', 20),   'PRODPAT',  'HOMEBLD08'),
    ('HOMECARE',    'HM',       CONVERT(datetime, '2017-09-01 00:00:00.000', 20),   CONVERT(datetime, '2017-09-30 00:00:00.000', 20),   'PRODPAT',  'HOMEBLD09'),
    ('HOMECARE',    'HQ',       CONVERT(datetime, '2017-04-01 00:00:00.000', 20),   CONVERT(datetime, '2017-04-30 00:00:00.000', 20),   'PRODPAT',  'HOMEDRG04HM'),
    ('HOMECARE',    'HM',       CONVERT(datetime, '2017-05-01 00:00:00.000', 20),   CONVERT(datetime, '2017-05-31 00:00:00.000', 20),   'PRODPAT',  'HOMEDRG05HM'),
    ('HOMECARE',    'HM',       CONVERT(datetime, '2017-06-01 00:00:00.000', 20),   CONVERT(datetime, '2017-06-30 00:00:00.000', 20),   'PRODPAT',  'HOMEDRG06HM'),
    ('HOMECARE',    'HM',       CONVERT(datetime, '2017-07-01 00:00:00.000', 20),   CONVERT(datetime, '2017-07-31 00:00:00.000', 20),   'PRODPAT',  'HOMEDRG07HM'),
    ('HOMECARE',    'HM',       CONVERT(datetime, '2017-08-01 00:00:00.000', 20),   CONVERT(datetime, '2017-08-31 00:00:00.000', 20),   'PRODPAT',  'HOMEDRG08HM'),
    ('HOMECARE',    'HM',       CONVERT(datetime, '2017-09-01 00:00:00.000', 20),   CONVERT(datetime, '2017-09-30 00:00:00.000', 20),   'PRODPAT',  'HOMEDRG09HM'), 
    ('111824',      'UR',       CONVERT(datetime, '2017-09-22 00:00:00.000', 20),   CONVERT(datetime, '2017-09-22 00:00:00.000', 20),   'OP',   'OP1118240003'),
    ('111824',      'NL',       CONVERT(datetime, '2017-04-19 00:00:00.000', 20),   CONVERT(datetime, '2017-04-19 00:00:00.000', 20),   'OP',   'OP1118240001'),
    ('111824',      'MS',       CONVERT(datetime, '2017-06-30 00:00:00.000', 20),   CONVERT(datetime, '2017-06-30 00:00:00.000', 20),   'OP',   'OP1118240002'),
    ('111824',      'MS',       CONVERT(datetime, '2017-04-24 00:00:00.000', 20),   CONVERT(datetime, '2017-04-24 00:00:00.000', 20),   'IP',   'IP1118240001'),
    ('111824',      'MS',       CONVERT(datetime, '2017-04-28 00:00:00.000', 20),   CONVERT(datetime, '2017-04-28 00:00:00.000', 20),   'IP',   'IP1118240005'),
    ('111824',      'MS',       CONVERT(datetime, '2017-04-27 00:00:00.000', 20),   CONVERT(datetime, '2017-04-27 00:00:00.000', 20),   'IP',   'IP1118240004'),
    ('111824',      'MS',       CONVERT(datetime, '2017-04-26 00:00:00.000', 20),   CONVERT(datetime, '2017-04-26 00:00:00.000', 20),   'IP',   'IP1118240003'),
    ('111824',      'MS',       CONVERT(datetime, '2017-04-25 00:00:00.000', 20),   CONVERT(datetime, '2017-04-25 00:00:00.000', 20),   'IP',   'IP1118240002');
GO

IF EXISTS (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'UTab')
DROP TABLE UTab;
GO

CREATE TABLE UTab 
    (MRN varchar(20), SIDate DATETIME, LSPEC varchar(2), Source varchar(20), Enum varchar(20), Iteration varchar(20));
GO

INSERT INTO UTab 
    (MRN, SIDate, LSPEC, Source, Enum, Iteration) 
VALUES 
('HOMECARE', CONVERT(datetime, '2017-04-20 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-04-20 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-04-20 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-04-20 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-04-20 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-04-20 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-04-30 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-04-30 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-04-30 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-04-20 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-04-30 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-04-30 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-17 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-04-30 00:00:00.000', 20), 'HQ', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-04-30 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-04-30 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-30 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-01 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-01 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-01 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-01 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-01 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-01 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-30 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-01 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-06-26 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-30 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-30 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-04 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-04 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-04 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-04 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-04 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-04 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-04 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-04 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-04 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-04 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-04 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-04 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-04 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-04 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-04 00:00:00.000', 20), 'HM', 'N', NULL, NULL), 
('HOMECARE', CONVERT(datetime, '2017-05-04 00:00:00.000', 20), 'HM', 'N', NULL, NULL),
('111824', CONVERT(datetime, '2017-04-21 00:00:00.000', 20), 'MS', 'IP', NULL, NULL), 
('111824', CONVERT(datetime, '2017-04-24 00:00:00.000', 20), 'NL', 'OP', NULL, NULL), 
('111824', CONVERT(datetime, '2017-04-27 00:00:00.000', 20), 'NL', 'OP', NULL, NULL), 
('111824', CONVERT(datetime, '2017-04-20 00:00:00.000', 20), 'NL', 'OP', NULL, NULL), 
('111824', CONVERT(datetime, '2017-04-20 00:00:00.000', 20), 'NL', 'OP', NULL, NULL), 
('111824', CONVERT(datetime, '2017-04-20 00:00:00.000', 20), 'NL', 'OP', NULL, NULL);
GO

SELECT * FROM ETab
WHERE Source = 'PRODPAT' AND LSPEC = 'HM' 
GO

SELECT * FROM UTab  
WHERE LSPEC = 'HM';
GO

IF EXISTS (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '__Tmp')
DROP TABLE __Tmp;
GO
Run Code Online (Sandbox Code Playgroud)

我有一个C#应用程序,用户在运行时请求certian匹配子句.使用用户指定的信息,我生成一些执行和更新的SQL UTab.

通过生成的SQL,我想执行一些匹配其更新[UTab].[Enum]基于链接字段[MRN]是否[UTab].[SIDate]内谎言[ETab].[ADT][ETab].[SDT]+ -这是由用户指定几天之前或之后.因此,用户可以指定两个命令,第一个:

MatchCmd:MRN,LSPEC:ETab:UTab:ADT:SDT:SIDate:0:1:'Iteration#1':WHERE [UTab].[Source] = 'OP' AND [UTab].[LSPEC] = [ETab].[LSPEC] 
Run Code Online (Sandbox Code Playgroud)

这是说,比赛就MRNLSPEC从源表ETab,更新UTab哪里SIDate > ADT - 0 day(s)SIDate < SDT + 1 day(s)在哪里[UTab].[Source] = 'OP'-我与"迭代次数"标志的任何比赛Iteration#1.

我的代码生成以下SQL:

;WITH cte AS (
    SELECT [ETab].[Enum] AS Enum, 
           [ETab].[MRN] AS Link, 
           [ETab].[ADT] AS ADT, 
           [ETab].[SDT] AS SDT, 
           [UTab].[SIDate] AS DT, 
           [ETab].[MRN] AS [MRN], 
           [ETab].[LSPEC] AS [LSPEC], 
           [ETab].[Source] AS [Source], 
           ROW_NUMBER() OVER (PARTITION BY [UTab].[MRN], [UTab].[LSPEC], [UTab].[SIDate] 
                ORDER BY ABS(DATEDIFF(mi, [UTab].[SIDate], [ETab].[ADT]))) AS Idx, 
           ABS(DATEDIFF(mi, [UTab].[SIDate], [ETab].[ADT])) AS Diff 
    FROM [UTab] 
        LEFT JOIN [ETab] ON [UTab].[MRN] = [ETab].[MRN] 
    WHERE ([UTab].[SIDate] BETWEEN 
        DATEADD(dd, -0, [ETab].[ADT]) AND 
        DATEADD(dd, 1, [ETab].[SDT]) AND [Iteration] IS NULL) 
            AND ETab.Source = 'OP' 
)  SELECT * 
   INTO __Tmp 
   FROM cte; 
GO
Run Code Online (Sandbox Code Playgroud)

获取符合条件的所有记录(在时间窗口内放置并遵守自定义where子句).然后我更新[UTab].[Enum][UTab].[Iteration]通过另一个生成的查询

UPDATE [UTab] 
SET [ENum] = [__Tmp].[ENum], [Iteration] = N'Iteration#1' 
--SELECT __Tmp.ENum, __Tmp.Link, __Tmp.LSPEC, __Tmp.ADT, __Tmp.SDT, __Tmp.DT, __Tmp.Idx 
FROM [UTab] AS up 
    INNER JOIN [__Tmp] 
        ON [up].[MRN] = [__Tmp].[Link] 
           AND [up].[SIDate] = [__Tmp].[DT] 
           AND [up].[LSPEC] = [__Tmp].[LSPEC] 
WHERE __Tmp.Idx = 1;
Run Code Online (Sandbox Code Playgroud)

这似乎工作正常,但有些问题:

问:我使用的方法/ SQL有什么明显的问题吗?

谢谢你的时间.

小智 3

CTE 的用法对我来说有点奇怪,因为在后续查询中您并没有真正使用它做太多事情。我会将其移至更新。

该查询并未真正加入Source。我不确定它是否有意这样做。如果 UTab 有多个 MRN/LSPEC 组合源,则可能会导致问题。

所以,我想出了类似的东西:

DECLARE @ADT_Adjustment INT = 0;
DECLARE @SDT_Adjustment INT = 1;
DECLARE @Iteration INT = 1;

WITH SequencedJoin AS (
    SELECT
        ETab.MRN, ETab.LSPEC, ETab.ADT, ETab.SDT, UTab.SIDate, ETab.Enum, ETab.[Source], UTab.Enum AS WriteEnum, UTab.Iteration AS WriteIteration
    ,   DENSE_RANK() OVER ( 
            PARTITION BY UTab.MRN, UTab.LSPEC, UTab.[Source], UTab.SIDate 
            ORDER BY ABS( DATEDIFF( MINUTE, UTab.SIDate, ETab.ADT ) ) 
        ) AS Ordinal
    FROM
        @UTab AS UTab
    JOIN    @ETab AS ETab ON (
            ETab.MRN = UTab.MRN
        AND ETab.LSPEC = UTab.LSPEC
        AND ETab.[Source] = UTab.[Source]
        AND UTab.SIDate BETWEEN DATEADD( dd, -@ADT_Adjustment, ETab.ADT ) AND DATEADD( dd, @SDT_Adjustment, ETab.SDT )
        )
    WHERE
        UTab.Iteration IS NULL
)
UPDATE
    SequencedJoin
SET
    WriteEnum = SequencedJoin.Enum
,   WriteIteration = N'Iteration#' + CAST( @Iteration AS VARCHAR( 2 ) )
WHERE
    SequencedJoin.[Source] = 'OP'
AND SequencedJoin.Ordinal = 1
Run Code Online (Sandbox Code Playgroud)