我有两个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专家可以回顾并告诉我我做错了吗?
答案 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'
第二个查询中有更多行,因为您要加入多个列,这可能是您获取更多记录的原因。在您的第一个查询中,您没有加入另一个表格。