CTE返回了不正确的结果

时间:2019-02-07 09:11:42

标签: sql tsql

[最初的帖子的道歉,没有创建表的DDL / DML语句-现在已修复]

我正在创建一个数据库,该数据库实质上记录了本地设施的检查结果。如果“检查”可以识别出故障,则有时可能导致“案件”被提出。案件也可以在没有检查的情况下提出,例如,如果有公众投诉。一项检查可能导致举起一个以上的案件-例如,如果该设施是一个本地公园,则可能是由于一项检查而引起的案件是(a)割草不良和(b)垃圾箱未被清空。

一个案例不能导致检查,但可能导致进一步的案例,因此在我的“案例”表中,我有DerivedFromInspectionID和DerivedFromCaseID列。

有两个表:检查表和GMCase(用于“地面维护案例”记录)

可以如下创建表的显着部分:


CREATE TABLE [Inspection](
    [InspectionID] [int] NOT NULL PRIMARY KEY,
    [InspectionDate] [datetime] NULL,
    [InspectionType] [varchar](10) NULL
    )

CREATE TABLE [GMCase](
    [CaseID] [int] NOT NULL PRIMARY KEY,
    [CaseDate] [datetime] NULL,
    [CaseType] [varchar](20) NULL,
    [DerivedFromCaseID] [int] NULL CONSTRAINT fk_Case_Case FOREIGN KEY REFERENCES GMCase (CaseID),
    [DerivedFromInspectionID] [int] NULL CONSTRAINT fk_Case_Inspection FOREIGN KEY REFERENCES Inspection(InspectionID)
    )


INSERT INTO Inspection(InspectionID, InspectionDate,InspectionType)
VALUES 
(2,GETDATE(),'Scheduled'),
(3,GETDATE(),'Scheduled'),
(5,GETDATE(),'Ad-hoc')


INSERT INTO GMCase (CaseID,CaseDate,CaseType,DerivedFromCaseID,DerivedFromInspectionID)
VALUES
(1 , GETDATE(),'Compliment',NULL,NULL),
(2, GETDATE(),'Complaint',NULL,2),
(3,GETDATE(),'Instruction',2,NULL),
(5,GETDATE(),'Rectification',3,NULL),
(14,GETDATE(),'Complaint',NULL,2)               


我想创建一个显示

链的视图
[Inspection1] (Optionally)
    >>> Case1 
        >>> Case2 
            >>> Case3. 

当查看“案例”或“检查”详细信息时,将在数据库应用程序中使用它。

在应用程序中,我需要能够查看链中的任何情况,并查看其如何适合该链。因此,如果我看一下Case2,它应该显示上面的所有项目。

为了获取源数据,我最初创建了一个包含UNION查询的视图,以将Inspection和GMCase表中的等效列组合在一起。由于我需要能够识别每个案例/检查,因此我将CaseID和InspectionID引入到了最初的两个单独的列中,但是我认为只有一个ID列会很有用。我想确保此ID上没有明显的重复(在Inspection 2中包含2,在Case2中也包含2),因此我想到了将ID如果是InspectionID设为负数的想法(也许这是一个错误吗?)< / p>

我添加了一个“级别”列,以帮助确定案件是在根级别还是从检查派生,并作为CTE中级别计算的起点。

我还添加了一个名为RootCase的列,对于“检查”,该列使我可以查看记录有链接到“检查”的GMCase(如果有)。举例来说,这是为了让我看一下案例3,我可以看到它最终源自检查2,因为它的根本原因与检查2的RootCase相同。如果这是一个错误...

该视图的SQL如下:


CREATE VIEW vwCaseHierarchySource 
AS
    SELECT CaseID, 
    CaseDate, 
    CaseType,
    ISNULL(-g.DerivedFromInspectionID,g.DerivedFromCaseID) AS ParentCaseID,
    CASE WHEN g.DerivedFromCaseID IS NULL AND g.DerivedFromInspectionID IS NULL THEN 0 ELSE 1 END AS [Level],
    CaseID AS RootCase
    FROM GMCase g
    UNION
    SELECT -i.InspectionID
          ,i.InspectionDate
          ,CONVERT(VARCHAR(20),i.InspectionType + ' inspection') AS CaseType
          ,NULL AS ParentCaseID
          ,CASE WHEN g.CaseID IS NULL THEN 0 ELSE 1 END AS [Level]
          ,g.CaseID AS RootCase
    FROM Inspection i
    LEFT JOIN GMCase g
    ON i.InspectionID = g.DerivedFromInspectionID


然后,我尝试了多种创建CTE的方法来显示此层次结构。 CTE不是我的专长,我记不住我尝试过的所有内容,但是下面是我目前的工作。

我怀疑我的问题是,由于检查可能导致(在我的样本数据中确实)导致不止一种情况,因为每当我使用CTE时,我都会获得正确的信息,但是还有不正确的信息。如果我尝试获取案例2的结果,那么我将获得案例2的层次结构,还可以获得案例14的行。如果我尝试对案例14,那么我将获得该结果,以及案例2的所有行。

这是CTE:

CREATE VIEW [dbo].[vwCaseInspectionHierarchy] 
AS

WITH CaseList AS 
(
SELECT
    CaseID,
    CaseDate,
    CaseType,
    ParentCaseID,
    RootCase,
    RootCase.[Level]
FROM vwCaseHierarchySource RootCase
WHERE RootCase.ParentCaseID IS NULL

UNION ALL

SELECT
    ChildCase.CaseID,
    ChildCase.CaseDate,
    ChildCase.CaseType,
    ChildCase.ParentCaseID,
    CaseList.RootCase,
    CaseList.[Level]+1
FROM vwCaseHierarchySource ChildCase
INNER JOIN CaseList ON
    ChildCase.ParentCaseID=CaseList.CaseID
)

SELECT * 
      ,REPLICATE(' ',[Level]*5) +   CaseType AS IndentedCaseType 
FROM CaseList


我的代码对其进行测试:

SELECT *
FROM [vwCaseInspectionHierarchy] 
WHERE RootCase=2

有人可以帮助我吗?抱歉,发表了很长的文章,但希望我已经包括了所有相关内容...

安德鲁

1 个答案:

答案 0 :(得分:1)

我认为您实际上不需要这种观点。

只需对表本身进行递归CTE即可解决问题。

您可以在两个表中使用类型字符串作为递归种子。

示例代码段

declare @Inspection table (InspectionID int primary key, InspectionDate datetime, InspectionType varchar(30));
declare @GMCase table (CaseID int primary key, CaseDate date, CaseType varchar(30), DerivedFromCaseID int, DerivedFromInspectionID int);

insert into @Inspection (InspectionID, InspectionDate, InspectionType) values
(102, '2019-01-22 00:00:00.000', 'Scheduled'),
(103, '2019-02-06 14:25:55.133', 'Scheduled'),
(105, '2019-02-06 16:59:04.820', 'Ad-hoc');

insert into @GMCase (CaseID, CaseDate, CaseType, DerivedFromCaseID, DerivedFromInspectionID) values
(1,  '2019-01-23', 'Compliment', NULL, NULL),
(2,  '2018-12-04', 'Complaint', NULL, 102),
(3,  '2018-12-04', 'Instruction', 2, NULL),
(5,  '2018-12-21', 'Rectification', 3, NULL),
(14, '2019-02-06', 'Complaint', NULL, 2),
(15, '2019-02-07', 'Compliment', NULL, NULL),
(16, '2019-02-08', 'Complaint', 15, NULL);

 with RCTE as
(
   -- Seeding the recursive CTE
   select i.InspectionID, n as Lvl, t.CaseID as RootCaseID, case when n = 1 then t.CaseID end as CaseID, t.DerivedFromCaseID, iif(n=0, i.InspectionType, t.CaseType) as [Type]
   from @GMCase t
   left join @Inspection i ON i.InspectionID = t.DerivedFromInspectionID
   cross join (values (0),(1)) nums(n)
   where t.DerivedFromCaseID is null

   union all

   select r.InspectionID, r.Lvl + 1, r.RootCaseID, t.CaseID, t.DerivedFromCaseID, t.CaseType 
   from RCTE r
   join @GMCase t on t.DerivedFromCaseID = r.CaseID
)
select c.RootCaseID, c.CaseID, c.InspectionID, t.CaseDate,
concat(replicate(' ',c.Lvl*5),COALESCE([Type],'Inspection')) AS IndentedType 
from RCTE c
left join @GMCase t on t.CaseID = c.CaseID
order by c.RootCaseID, c.Lvl;

结果:

RootCaseID  CaseID  InspectionID    CaseDate    IndentedType
1           NULL        NULL        NULL        Inspection
1           1           NULL        2019-01-23       Compliment
2           NULL        102         NULL        Scheduled
2           2           102         2018-12-04       Complaint
2           3           102         2018-12-04            Instruction
2           5           102         2018-12-21                 Rectification
14          NULL        NULL        NULL        Inspection
14          14          NULL        2019-02-06       Complaint
15          NULL        NULL        NULL        Inspection
15          15          NULL        2019-02-07       Compliment
15          16          NULL        2019-02-08            Complaint