通过连接多个表来获取信息

grabbing information by joining multiple tables

这会有点复杂。让我从我的 table 开始。

clients [src = 0]
---------
clientID       code         company
---------      -------      ---------
1              ABC          ABC Corp
2              DEF          DEF Corp


carriers [src = 1]
---------
clientID       code       company
---------      -------    -------
1              ABC         ABC Inc.
2              JHI         JHI Inc. 


link
--------
contactID        uID      src
---------        -----    ----
1                 1        0
1                 1        1
1                 2        0

contact info
--------------
contactID      fname      lname
---------     -------     --------
1             John        Smith
2              Quincy     Jones

所以,我正在尝试在 link table 上搜索 "ABC"。 link table 基本上需要根据 link.src 列加入运营商或客户 table。它应该找到两个匹配项,一个在客户中,一个在运营商中,但由于两者都解析为 1 的 contactID (links table),我应该查询联系信息 table和 return

找到 1 条记录: 约翰·史密斯

我希望这是有道理的。非常感谢任何帮助!

这是一种使用 left join 的方法:

select co.*
from link l left join
     clients cl
     on l.src = 0 and l.uid = cl.code left join
     carriers ca
     on l.src = 1 and l.uid = ca.code left join
     contacts co
     on l.contactid = co.contactid
where 'ABC' in (co.code, cl.code)

这是另一种方法。首先,您 UNION ClientsCarriers 表并添加一个新列 ContactType 以区分它们。 Clients使用0Carriers使用1,与src相同。然后执行 LEFT JOIN 以获得所需的结果。

;WITH Clients(ClientID, Code, Company) AS(
    SELECT 1, 'ABC', 'ABC Corp' UNION ALL
    SELECT 2, 'DEF', 'DEF Corp'
)
,Carriers(ClientID, Code, Company) AS(
    SELECT 1, 'ABC', 'ABC Inc.' UNION ALL
    SELECT 2, 'JHI', 'JHI Inc.'
)
,Link(ContactId, UID, Src) AS(
    SELECT 1, 1, 0 UNION ALL
    SELECT 1, 1, 1 UNION ALL
    SELECT 1, 2, 0
)
,ContactInfo(ContactID, FName, LName) AS(
    SELECT 1, 'John', 'Smith' UNION ALL
    SELECT 2, 'Quincy', 'Jones'
)
-- START
,Contact(ContactID, ContactType, Code, Company) AS(
    SELECT
        ClientID, 0, Code, Company
    FROM Clients
    UNION ALL
    SELECT
        ClientID, 1, Code, Company
    FROM Carriers
)
SELECT DISTINCT 
    ci.FName,
    ci.LName
FROM Link l
LEFT JOIN Contact c
    ON c.ContactID = l.UID
    AND c.ContactType = l.src
LEFT JOIN ContactInfo ci
    ON ci.ContactID = c.ContactID
WHERE
    c.Code = 'ABC'

从建模视角看这个。您有两个 table,每个都具有相同类型的数据,即实体 company。他们之间的唯一区别是他们的角色或与贵公司的关系。那为什么不把它们都放在同一个桶里呢?

Companies:
ID   code   Name
--   ----   ---------
1    ABC    ABC Corp
2    DEF    DEF Corp
3    JHI    JHI Inc.

如果特定公司只能是客户或承运人,则该指定可以放在 Companies table 中。由于显然一家公司可以同时兼具两者,因此该名称进入单独的 table。下图显示公司1'ABC'既是客户('L')又是承运人('R'),公司2只是客户,公司3只是承运人

CompanyRoles:
CompanyID   Type
---------   ----
        1   'L'
        1   'R'
        2   'L'
        3   'R'

没有必要因为一个公司可以扮演多个角色而保留相同数据的多个副本。如果有依赖于角色的数据,即在客户端维护但不为运营商维护的数据,反之亦然,则 subtables 可以保留该数据。

至于联系人,如果一家公司只有一个联系人,无论职位如何,联系人参考可以添加到 Companies table。如果联系人依赖于角色,则会将其添加到 CompanyRoles table.

CompanyRoles:
CompanyID   Type   ContactID
---------   ----   ---------
        1   'L'            1
        1   'R'            2
        2   'L'            3
        3   'R'            4

想查看客户列表吗?

select  c.ID as ClientID, c.Code as ClientCode, c.Name as ClientName,
        ci.ContactName
from    Companies c
join    CompanyRoles cr
    on  cr.CompanyID = c.ID
    and cr.Type      = 'L'
left join Contacts ct    -- In case no contact is currently defined
    on  ct.ContactID = cr.ContactID
join    ClientSpecificData csd
    on  csd.ClientID = c.ID;

想查看运营商列表吗?

select  c.ID as CarrierID, c.Code as CarrierCode, c.Name as CarrierName,
        ci.ContactName
from    Companies c
join    CompanyRoles cr
    on  cr.CompanyID = c.ID
    and cr.Type      = 'R'
left join Contacts ct    -- In case no contact is currently defined
    on  ct.ContactID = cr.ContactID
join    CarrierSpecificData csd
    on  csd.ClientID = c.ID;

您可以针对最后两个查询创建视图,以便为那些只处理客户或运营商的应用程序提供单一数据源。视图上的触发器可以根据需要处理传入的 DML 语句,以将数据路由到适当的 tables。

如您所见,查询简洁明了。数据完整性很容易,可扩展性不是问题。您还想要什么?