外部結合の結果が想定と異なるが理由がピンとこない
SQLServerのお勉強で躓いています。
やろうとした事は no, timestamp の2列から成る'table_a'に、 no, datetime, value の3列から成る'table_b'を左外部結合するという事です(両テーブルとも no, datetime がプライマリキー)。
結合条件は下記の通りです。
- no: '='比較
- timestamp:'table_b'の timestamp の中で、'table_a'の timestamp 以下の最大の timestamp
あまり上手い説明ではないので、具体例として下記コードをご覧下さい。
IF object_id('table_a') IS NOT NULL
DROP TABLE table_a;
CREATE TABLE table_a (
no INTEGER not null
,timestamp DATE not null
,CONSTRAINT pk_table_a PRIMARY KEY CLUSTERED (no, timestamp)
);
IF object_id('table_b') IS NOT NULL
DROP TABLE table_b;
CREATE TABLE table_b (
no INTEGER not null
,timestamp DATE not null
,value INTEGER not null
,CONSTRAINT pk_table_b PRIMARY KEY CLUSTERED (no, timestamp)
);
BEGIN TRANSACTION;
INSERT INTO table_a (no, timestamp)
VALUES (1, '2018-01-01')
,(1, '2018-01-04')
,(1, '2018-01-05')
,(2, '2018-01-01')
,(2, '2018-01-03')
,(2, '2018-01-09')
,(3, '2018-01-10')
,(3, '2018-01-11')
,(3, '2018-01-12')
;
INSERT INTO table_b (no, timestamp, value)
VALUES (1, '2018-01-01', 101)
,(1, '2018-01-02', 102)
,(2, '2018-01-02', 202)
,(3, '2017-01-01', 301)
,(3, '2018-01-12', 312)
;
COMMIT;
SELECT *
FROM table_a
;
SELECT *
FROM table_b
;
-- Query A: I can get what I want.
SELECT A.no
,A.timestamp
,B.value
FROM (
SELECT A.no
,A.timestamp
,(SELECT MAX(B.timestamp)
FROM table_b as B
WHERE B.no = A.no
AND B.timestamp <= A.timestamp) as a_b_timestamp
FROM table_a AS A
) as A
LEFT OUTER JOIN table_b AS B
ON A.no = B.no
AND A.a_b_timestamp = B.timestamp
WHERE A.no in (1, 2)
;
-- Query B: This query's result set is the same with A.
SELECT A.no
,A.timestamp
,B.value
FROM table_a AS A
LEFT OUTER JOIN table_b AS B
ON A.no = B.no
AND B.timestamp = (SELECT MAX(B.timestamp)
FROM table_b as B
WHERE B.no = A.no
AND B.timestamp <= A.timestamp)
WHERE A.no in (1, 2)
;
-- Query C: The result set is far from what I expected, but I do not know reason.
SELECT A.no
,A.timestamp
,B.value
FROM table_a AS A
LEFT OUTER JOIN table_b AS B
ON A.no = B.no
AND A.timestamp = (SELECT MAX(B.timestamp)
FROM table_b as B
WHERE B.no = A.no
AND B.timestamp <= A.timestamp)
WHERE A.no in (1, 2)
;
テーブルに以下のデータが準備されます。
table_a:
no timestamp
1 2018-01-01
1 2018-01-04
1 2018-01-05
2 2018-01-01
2 2018-01-03
2 2018-01-09
3 2018-01-10
3 2018-01-11
3 2018-01-12
table_b:
no timestamp value
1 2018-01-01 101
1 2018-01-02 102
2 2018-01-02 202
3 2017-01-01 301
3 2018-01-12 312
コード内にQuery A, B, C とコメントされたクエリがありますが、得られる結果セットは以下の通りです。私がほしかったのは A, B なのですが、 C だけが異なる結果セットを返しています。
Query A,B の結果セット(これが欲しかった!):
no timestamp value
1 2018-01-01 101
1 2018-01-04 102
1 2018-01-05 102
2 2018-01-01 NULL
2 2018-01-03 202
2 2018-01-09 202
Query C の結果セット(ほしいもの違う):
no timestamp value
1 2018-01-01 101
1 2018-01-01 102
1 2018-01-04 NULL
1 2018-01-05 NULL
2 2018-01-01 NULL
2 2018-01-03 NULL
2 2018-01-09 NULL
困っているのは C の結果がなぜ上のようになるのかが上手く説明出来ない点です。
どなたか、理由をクリアに説明して頂けないでしょうか。