SQL Server:连接导致行太多

时间:2017-03-22 21:17:10

标签: sql sql-server-2014

我有两个SQL Server表。

第一个表名为Content,其中包含名为

的列
FileID, FileHighResolutionID, FileHighResolutionProID, FileVectorID

第二个表名为Analytics,其中包含一个名为FileID的列。此列包含Content中上述四个列之一的值。

执行以下内容......

SELECT 
    * 
FROM 
    Analytics a
WHERE 
    a.Created BETWEEN '2017-03-07' AND '2017-03-08'

产生782行。

但执行以下内容......

SELECT 
    * 
FROM 
    Analytics a
INNER JOIN 
    Content c ON (c.FileID = a.FileID OR c.FileHighResolutionID = a.FileID OR c.FileHighResolutionProID = a.FileID OR c.FileVectorID = a.FileID)
WHERE 
    a.Created BETWEEN '2017-03-07' AND '2017-03-08'

结果为843行。

我知道我的JOIN有问题,因为现在我有61条记录。我尝试了INNER JOIN,LEFT OUTER JOINS,RIGHT OUTER JOIN,但每个都会产生61个神秘的额外记录。

有些SQL专家可以回顾并告诉我我做错了吗?

3 个答案:

答案 0 :(得分:2)

您现在必须知道问题是OR匹配c中的多个列。每个匹配都会有一个单独的行。瞧!意外的行。

解决此问题的一种方法是使用“横向连接”。这就像一个相关的子查询,但它可以返回多个列和多行(这里不需要)。在SQL Server中,这是使用APPLY

实现的
SELECT a.*, c.*
FROM Analytics a CROSS APPLY
     (SELECT TOP 1 c.*
      FROM Content c 
      WHERE a.FileID IN (c.FileId, c.FileHighResolutionID, c.FileHighResolutionProID, c.FileVectorID)
    ) c
WHERE a.Created BETWEEN '2017-03-07' AND '2017-03-08';

这将返回任意匹配的行。您可以使用ORDER BY

获取特定行
SELECT a.*, c.*
FROM Analytics a CROSS APPLY
     (SELECT TOP 1 c.*
      FROM Content c 
      WHERE a.FileID IN (c.FileId, c.FileHighResolutionID, c.FileHighResolutionProID, c.FileVectorID)
      ORDER BY (CASE a.FileId WHEN c.FileId THEN 1 c.FileHighResolutionID THEN 2 c.FileHighResolutionProID THEN 3 c.FileVectorID THEN 4
                END)
    ) c
WHERE a.Created BETWEEN '2017-03-07' AND '2017-03-08';

注意:我同意对BETWEEN使用日期/时间值的问题的答案。这很危险,因为时间会导致误导逻辑。我强烈推荐以下其中一项:

WHERE a.Created = '2017-03-07'
WHERE a.Created >= '2017-03-07' AND a.Created < '2017-03-09';

答案 1 :(得分:2)

如果您不需要Content表中的数据,则可以选择EXISTS

SELECT *
FROM Analytics AS A
WHERE A.Created >= '2017-03-07'
    AND A.Created < '2017-03-08'
    AND EXISTS (
        SELECT *
        FROM Content AS C
        WHERE A.FileID IN (C.FileID, C.FileHighResolutionID, C.FileHighResolutionProID, C.FileVectorID)
        );

EXISTS会在true条件下产生false / WHERE,并且不会创建欺骗行为。

答案 2 :(得分:0)

另一个不好的做法是在日期过滤时在WHERE子句中使用BETWEEN

WHERE a.Created >= '20170307' AND a.Created < '20170308'

第二个查询中有更多行,因为您要加入多个列,这可能是您获取更多记录的原因。在您的第一个查询中,您没有加入另一个表格。