完整外连接的顺序产生不同数量的结果行。为什么?

时间:2014-10-22 15:33:33

标签: sql sql-server outer-join

我正在处理两个表AB。表A表示权益证券,表B有许多关于证券的详细信息。

例如,当B.Item = 5301时,该行指定给定安全性的价格。当B.Item = 9999时,该行指定给定安全性的股息。我试图让价格和红利在同一行。为了实现这一点,我FULL JOINedB两次到表A

SELECT * 
FROM   a a 
       FULL JOIN (SELECT * 
                  FROM   b) b 
              ON b.code = a.code 
                 AND b.item = 3501 
       FULL JOIN (SELECT * 
                  FROM   b) b2 
              ON b2.code = a.code 
                 AND b.item = 9999 
                 AND b2.year_ = b.year_ 
                 AND b.freq = b2.freq 
                 AND b2.seq = b.seq 
WHERE  a.code IN ( 122514 ) 

联接条款中的其他字段,例如Year_FreqSeq只是确保价格和股息的日期匹配。 A.Code只标识单个安全性。

我的问题是当我翻转完整联接的顺序时,我会得到不同数量的结果。因此,如果b.Item = 9999出现在b.Item 2501之前,我会得到一个结果。反过来我得到2个结果。我意识到表B对于红利的安全性122514没有任何条目,但有两个价格条目。

当首先指定价格时,我得到的价格和股息字段都是null。但是,在首先指定股息时,我会为股息字段获取NULLs,为价格字段获取nulls

为什么不出现两个价格条目?我希望他们在FULL JOIN

中这样做

1 个答案:

答案 0 :(得分:3)

这是因为你的第二个FULL OUTER JOIN指的是你的第一个FULL OUTER JOIN。这意味着更改它们的顺序正在对查询进行根本性更改。

这是一些伪SQL,演示了它是如何工作的:

DECLARE @a TABLE (Id INT, Name VARCHAR(50));
INSERT INTO @a VALUES (1, 'Dog Trades');
INSERT INTO @a VALUES (2, 'Cat Trades');
DECLARE @b TABLE (Id INT, ItemCode VARCHAR(1), PriceDate DATE, Price INT, DividendDate DATE, Dividend INT);
INSERT INTO @b VALUES (1, 'p', '20141001', 100, '20140101', 1000);
INSERT INTO @b VALUES (1, 'p', '20141002', 50, NULL, NULL);
INSERT INTO @b VALUES (2, 'c', '20141001', 10, '20141001', 500);
INSERT INTO @b VALUES (2, 'c', NULL, NULL, '20141002', 300);

--Same results
SELECT a.*, b1.*, b2.* FROM @a a FULL OUTER JOIN @b b1 ON b1.Id = a.Id AND b1.ItemCode = 'p' FULL OUTER JOIN @b b2 ON b2.Id = a.Id AND b2.ItemCode = 'c';
SELECT a.*, b2.*, b1.* FROM @a a FULL OUTER JOIN @b b1 ON b1.Id = a.Id AND b1.ItemCode = 'c' FULL OUTER JOIN @b b2 ON b2.Id = a.Id AND b2.ItemCode = 'p';

--Different results
SELECT a.*, b1.*, b2.* FROM @a a FULL OUTER JOIN @b b1 ON b1.Id = a.Id AND b1.ItemCode = 'p' FULL OUTER JOIN @b b2 ON b2.Id = a.Id AND b2.ItemCode = 'c' AND b2.DividendDate = b1.PriceDate;
SELECT a.*, b2.*, b1.* FROM @a a FULL OUTER JOIN @b b1 ON b1.Id = a.Id AND b1.ItemCode = 'c' FULL OUTER JOIN @b b2 ON b2.Id = a.Id AND b2.ItemCode = 'p' AND b2.DividendDate = b1.PriceDate;