视图中四个表的 SQL Server 条件连接

Posted

技术标签:

【中文标题】视图中四个表的 SQL Server 条件连接【英文标题】:SQL Server conditional join of four tables in a View 【发布时间】:2016-12-01 13:19:37 【问题描述】:

这个让我发疯,甚至不可能。我在下面列出了四个表。为简洁起见,我删除了不重要的列、索引、键、外键等。

CREATE TABLE Client(
    ClientID uniqueidentifier ROWGUIDCOL NOT NULL DEFAULT (newid()),
    ClientName varchar(250) not null
);
GO

CREATE TABLE Instance(
    InstanceID uniqueidentifier ROWGUIDCOL NOT NULL DEFAULT (newid()),
    ClientID uniqueidentifier not null, /* FK into Client */
    InstanceName varchar(48) not null
);
GO

CREATE TABLE Object(
    ObjectID uniqueidentifier ROWGUIDCOL NOT NULL DEFAULT (newid()),
    ClientID uniqueidentifier not null, /* FK into Client */
    InstanceID uniqueidentifier null,   /* FK into Instance */
    Path varchar(260) not null
);
GO

CREATE TABLE History(
    Timestamp datetime DEFAULT (getdate()),
    ClientID uniqueidentifier null,     /* if not null, references Client */
    InstanceID uniqueidentifier null,   /* if not null, references Instance */
    ObjectID uniqueidentifier null,     /* if not null, references Object */
    Details varchar(1024)
);
GO

我正在尝试在历史记录表上创建一个视图。视图中棘手的列是 ClientName。如果 History.ClientID 不为空,那么这很容易。但是如果 History.ClientID is null 而 ObjectID is not null,则需要通过 History.ObjectID->Object.ClientID->Client.ClientName 获取 ClientName。

这是我能想到的最好的方法,如果 History.ClientID 不为 null,则该方法有效,但如果 History.ClientID 为 null,我不知道如何通过 ObjectID 获取 ClientName。我希望这一切都清楚了。

CREATE VIEW History_Report as
SELECT 
        H.TimeStamp,
        C.ClientName,
        Q.InstanceName,
        O.Path,
        H.Details
from 
    History H
    left join Instance Q ON (H.InstanceID = Q.InstanceID)
    left join Object O on (H.ObjectID = O.ObjectID)
    left join Client C on (H.ClientID = C.ClientID)
GO

这最好用游标完成吗?

【问题讨论】:

【参考方案1】:

我认为你的意思是这样的:

CREATE VIEW History_Report as
SELECT 
        H.TimeStamp,
        COALESCE(C.ClientName, CO.ClientName) ClientName,
        Q.InstanceName,
        O.Path,
        H.Details
from 
    History H
    left join Instance Q ON (H.InstanceID = Q.InstanceID)
    left join Object O on (H.ObjectID = O.ObjectID)
    left join Client C on (H.ClientID = C.ClientID)
    LEFT JOIN Client CO ON (O.ClientID = CO.ClientID)
GO

【讨论】:

太棒了!谢谢。我忘记了 COALESCE。【参考方案2】:

简单的方法是在查询中添加一个额外的join

CREATE VIEW History_Report as
SELECT 
        H.TimeStamp,
        isnull(C.ClientName, CO.ClientName) as ClientName,
        Q.InstanceName,
        O.Path,
        H.Details
from History H
    left join Instance Q
        on(H.InstanceID = Q.InstanceID)
    left join Object O
        on(H.ObjectID = O.ObjectID)
    left join Client C
        on(H.ClientID = C.ClientID)
    left join Client CO
        on(O.ClientID = CO.ClientID
          and H.ClientID is null    -- This will help limit duplicates
          )
GO

虽然您在以这种方式添加额外的joins 时需要注意重复项。在没有看到您的数据的情况下,这不是我们可以肯定地说的。

【讨论】:

以上是关于视图中四个表的 SQL Server 条件连接的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 是不是在复杂视图中传播 WHERE 条件?

sql server链接查询

如何根据非条件连接 2 个表的结果

Spring Aop中四个重要概念,切点,切面,连接点,通知

用于 4 个表的 SQL Server 2008 连接类型

如何将两个表与 SQL Server 中第二个表中引用同一列的两列连接起来