SQL Left Join返回的记录多于预期

时间:2016-05-30 00:41:28

标签: sql sql-server left-join

我正在尝试使用dbo.contact列加入两个表dbo.notescontactno,当我只运行dbo.contact的查询时

SELECT     
    contactno, date_recd
FROM         
    dbo.contact
WHERE     
    (date_recd > CONVERT(DATETIME, '2016-01-01 00:00:00', 102))
    AND (date_recd <= CONVERT(DATETIME, '2016-04-01 00:00:00', 102))

我收到了11526条记录,但当我加入notes

SELECT     
    dbo.contact.contactno, dbo.contact.date_recd, dbo.notes.noteline
FROM         
    dbo.contact 
LEFT OUTER JOIN
    dbo.notes ON dbo.contact.contactno = dbo.notes.contactno
WHERE     
    (dbo.contact.date_recd > CONVERT(DATETIME, '2016-01-01 00:00:00', 102)) 
    AND (dbo.contact.date_recd <= CONVERT(DATETIME, '2016-04-01 00:00:00', 102))

然后我得到了22276条记录。我不确定出错了什么。我想只让所有11526如何做到这一点?非常感谢任何帮助。

3 个答案:

答案 0 :(得分:2)

如果每个联系人只需要一个便笺,则可以使用outer apply

SELECT c.contactno, c.date_recd, n.noteline
FROM dbo.contact c OUTER APPLY
     (SELECT TOP 1 n.*
      FROM dbo.notes n 
      WHERE c.contactno = n.contactno
     ) n
WHERE (c.date_recd > CONVERT(DATETIME, '2016-01-01 00:00:00', 102)) AND
      (dc.date_recd <= CONVERT(DATETIME, '2016-04-01 00:00:00', 102));

通常子查询会有ORDER BY,指定您想要的注释。但是,您的查询并未指定多个注释中的哪一个是首选注释。

答案 1 :(得分:1)

是的,执行左连接会返回第一个表中的所有行,并仅返回第二个表中的匹配行。但是,如果第二个表中的多个行匹配,则它将返回两者,这可能导致第一个表中的行重复。

例如:

Table1
ID  Value
 1      A
 2      B
 3      C

Table2
ID  Value
 1      X
 1      Y
 2      Z

Select * from Table1 a
left join Table2 b
on a.ID = b.ID

返回:

ID  Value    ID  Value
 1      A     1     X
 1      A     1     Y
 2      B     2     Z
 3      C  Null  Null

其中总共有四行,即使示例中的Table1只有三行。要避免这种情况,您需要调整连接条件,以使每行最多匹配一个匹配项,或添加一些重复数据删除步骤。

答案 2 :(得分:0)

上面的答案很神奇,但我想发布修复我的问题的代码。所以我需要所有的11526条记录,但不仅是每个联系人的前1个noteline我想要所有的notelines所以我最终将记录连接成一个字符串。

Select  contact.contactno, 
STUFF(( Select '' + notes.noteline  FROM notes
 Where notes.contactno = contact.contactno 
order by notes.contactno for xml path (''),type).value('.','nvarchar(max)'),1,2,'') AS Notes 
From contact
WHERE 
(contact.date_recd > CONVERT(DATETIME, '2015-12-31 00:00:00', 102))
 AND
(contact.date_recd <= CONVERT(DATETIME, '2016-04-01 00:00:00', 102)) 
Group By contact.contactno;