【问题标题】:How to join tables when there are duplicates in right table右表有重复项时如何连接表
【发布时间】:2018-02-20 02:00:21
【问题描述】:

我有三张桌子。表 Cust 有一个 custID 字段,以及各种其他值(名称、地址等)

表列表具有单个列 ID。每个 ID 都是 Cust 表中的一个 custID 编辑:这样做的目的是过滤记录,将结果限制为 CustID 出现在列表中的结果。

所有三个表都已编入索引。

表 Trans 有一个 TransactionID 字段,一个保存客户 ID 的 Cust 字段,以及其他交易字段

编辑:我应该提到在某些情况下不会有交易记录。在这种情况下,我想要一行客户信息,其中交易字段为空或空白。

我想要一个查询返回列表中每个 ID 的客户和事务 ID。如果事务表中有多个匹配行,我希望每一个都包含在 3 中以及匹配的客户信息中。所以如果表格看起来像这样:

    Cust
ID        Name
01        John
02        Mary
03        Mike
04        Jane
05        Sue
06        Frank

    List
ID
01
03 
05
06

      Transact
TransID  CustId  Msg
21        01     There   
22        01     is
23        02     a
24        03     tide
25        04     in
26        04     the
27        05     affairs
28        05     of
29        05     men

我希望结果集是:

CustID   Name  TransID  Msg
01      John   21       There
01      John   22       is
03      Mike   24       tide
05      Sue    27       affairs
05      Sue    28       of
05      Sue    29       men
06      Frank  --       -- 

(其中 -- 表示 NULL 或 BLANK)

显然实际的表要大得多(数百万行),但这显示了模式,表 Transactions 中的每个项目与 List 表中的任何项目匹配,并与 Cust 表中的匹配字段匹配。如果没有匹配的 Transaction,List 表中每个 ID 的一行客户信息。 CustID 在 Cust 和 List 表中是唯一的,但在事务表中不是唯一的。

这需要在 2005 年以后的任何版本的 SQL Server 上工作,如果这很重要的话。

有什么建议吗?

【问题讨论】:

  • 我不太确定问题出在哪里,因为连接会带回与连接子句匹配的 all 记录。此外,列表似乎不属于这个组合,除非有你没有提到的目的。您可以直接从 cust 表连接到事务一。请更新您的问题并添加您尝试过的查询。如果您得到不正确的结果,我们可以尝试为您提供帮助。
  • 列表用于限制返回的 ID。在上面的玩具示例中,它阻止显示 CustID 值 2 或 4 的任何结果。在我的测试系统中,它将数万条记录减少到几百条,并且在客户端站点中,它减少了数百万条记录或交易表到 1-2 千个结果
  • 在一个适当的系统(外键、索引)中,没有那个列表你应该能够正常执行。你有什么努力让它发挥作用?
  • @eli,列表被用作替换导致主要性能问题的 IN 子句。它是动态创建的,并且只存在于一个查询中。我已经尝试过内连接和左连接,首先是 cust 表和首先是 trans 表,以及 trans 表的交叉应用(在 stackoverflow.com/questions/45766195/… 提出的建议的一部分)
  • 这些表有索引吗?

标签: sql-server join sql-server-2005 sql-server-2014


【解决方案1】:
;with cust (id, name) as
(
    select 1, 'John' union all
    select 2, 'Mary' union all
    select 3, 'Mike' union all
    select 4, 'Jane' union all
    select 5, 'Sue'
), list (id) as
(
    select 1 union all
    select 3 union all
    select 5
), transact (TransId, CustId, Msg) as
(
    select 21, 1, 'There '  
    union all select 22, 1, 'is'
    union all select 23, 2, 'a'
    union all select 24, 3, 'tide'
    union all select 25, 4, 'in'
    union all select 26, 4, 'the'
    union all select 27, 5, 'affairs'
    union all select 28, 5, 'of'
    union all select 29, 5, 'men'
)
select
    CustId = c.id,
    Name = c.Name,
    TransId = t.TransId,
    Msg = t.Msg
from cust c
inner join list l
    on c.id = l.id
inner join transact t
    on l.id = t.custid

产量:

CustId      Name TransId     Msg
----------- ---- ----------- -------
1           John 21          There 
1           John 22          is
3           Mike 24          tide
5           Sue  27          affairs
5           Sue  28          of
5           Sue  29          men

【讨论】:

  • 这几乎可以工作,但当列表和 cust 表中包含的 ID 没有匹配的 trans 行时,它不会给我想要的答案。我在最初的帖子中没有提到这一点。
  • @DavidSiegel 请更新您的帖子以包含此内容 - 大多数读者不会在这里找到它
  • 将连接更改为transactleft outer join 然后。这将包括所有客户/列表行,无论是否有交易
【解决方案2】:

除非我遗漏了什么,否则你只需要这样做:

Select   T.CustID, C.Name, T.TransID, T.Msg
From     Transact   T
Join     Cust       C   On  C.Id = T.CustId
Join     List       L   On  L.Id = C.Id
Order By T.CustID, T.TransID

【讨论】:

    猜你喜欢
    • 2018-12-27
    • 2012-06-05
    • 2020-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-25
    • 1970-01-01
    相关资源
    最近更新 更多