为什么 - 因为当您只有一个日期来连接 2 个表时,这就是连接的工作方式。要解决此问题,您需要创建除日期之外的关系,记住在任何时候收入记录的数量可能大于、小于或等于费用记录的数量。如果我们为收入中的每一行生成一个行号,并为支出中的每一行独立生成一个行号,那么我们可以在行号上加入收入和支出
例如
/*
CREATE TABLE INCOME (ID INT,DESCRIPTION VARCHAR(10),DT DATE,AMOUNT INT);
INSERT INTO INCOME VALUES
(1,'SALE','2016-08-30',100),
(2,'ROKY','2016-08-30',200),
(3,'KORIM','2016-08-30',300),
(4,'SALEVOUCHR','2016-08-30',400);
CREATE TABLE EXPENSES (ID INT,DESCRIPTION VARCHAR(10),DT DATE,AMOUNT INT);
TRUNCATE TABLE EXPENSES;
INSERT INTO EXPENSES VALUES
(1,'RENT','2016-08-30',100),
(2,'UTILITIES','2016-08-30',100);
/*
这段代码
SELECT S.DT,S.DESCRIPTION,S.AMOUNT, s.rn,T.DESCRIPTION,T.AMOUNT, t.rn1
FROM
(
SELECT I.DT,I.DESCRIPTION,I.AMOUNT,
@RN:=@RN + 1 RN
FROM (SELECT @RN:=0) RN,INCOME I
) S
LEFT OUTER JOIN
(SELECT E.DT,E.DESCRIPTION,E.AMOUNT,
@RN1:=@RN1 + 1 RN1
FROM (SELECT @RN1:=0) RN1, EXPENSES E
) T ON T.RN1 = S.RN AND T.DT = S.DT
WHERE S.DT IS NOT NULL
结果
+------------+-------------+--------+------+-------------+--------+------+
| DT | DESCRIPTION | AMOUNT | rn | DESCRIPTION | AMOUNT | rn1 |
+------------+-------------+--------+------+-------------+--------+------+
| 2016-08-30 | SALE | 100 | 1 | RENT | 100 | 1 |
| 2016-08-30 | ROKY | 200 | 2 | UTILITIES | 100 | 2 |
| 2016-08-30 | KORIM | 300 | 3 | NULL | NULL | NULL |
| 2016-08-30 | SALEVOUCHR | 400 | 4 | NULL | NULL | NULL |
+------------+-------------+--------+------+-------------+--------+------+
但这是不安全的,因为它假定收入总是多于支出项目
例如,如果我们再添加 3 个费用行
TRUNCATE TABLE EXPENSES;
INSERT INTO EXPENSES VALUES
(1,'RENT','2016-08-30',100),
(2,'UTILITIES','2016-08-30',100),
(3,'RATES','2016-08-30',100),(4,'SALARY','2016-08-30',100),(5,'INSURANCE','2016-08-30',100);
那么最后一个费用项目丢失导致
+------------+-------------+--------+------+-------------+--------+------+
| DT | DESCRIPTION | AMOUNT | rn | DESCRIPTION | AMOUNT | rn1 |
+------------+-------------+--------+------+-------------+--------+------+
| 2016-08-30 | SALE | 100 | 1 | RENT | 100 | 1 |
| 2016-08-30 | ROKY | 200 | 2 | UTILITIES | 100 | 2 |
| 2016-08-30 | KORIM | 300 | 3 | RENT | 100 | 3 |
| 2016-08-30 | SALEVOUCHR | 400 | 4 | UTILITIES | 100 | 4 |
+------------+-------------+--------+------+-------------+--------+------+
为了解决这个问题,我们可以像这样模拟完全连接
SELECT S.*,T.*
FROM
(
SELECT I.DT,I.DESCRIPTION,I.AMOUNT,
@RN:=@RN + 1 RN
FROM (SELECT @RN:=0) RN,INCOME I
) S
LEFT JOIN
(SELECT E.DT,E.DESCRIPTION,E.AMOUNT,
@RN1:=@RN1 + 1 RN1
FROM (SELECT @RN1:=0) RN1, EXPENSES E
) T ON T.RN1 = S.RN AND T.DT = S.DT
UNION
SELECT S.*,T.*
FROM
(
SELECT I.DT,I.DESCRIPTION,I.AMOUNT,
@RN3:=@RN3 + 1 RN3
FROM (SELECT @RN3:=0) RN3,INCOME I
) S
RIGHT JOIN
(SELECT E.DT,E.DESCRIPTION,E.AMOUNT,
@RN4:=@RN4 + 1 RN4
FROM (SELECT @RN4:=0) RN4, EXPENSES E
) T ON T.RN4 = S.RN3 AND T.DT = S.DT
结果
+------------+-------------+--------+------+------------+-------------+--------+------+
| DT | DESCRIPTION | AMOUNT | RN | DT | DESCRIPTION | AMOUNT | RN1 |
+------------+-------------+--------+------+------------+-------------+--------+------+
| 2016-08-30 | SALE | 100 | 1 | 2016-08-30 | RENT | 100 | 1 |
| 2016-08-30 | ROKY | 200 | 2 | 2016-08-30 | UTILITIES | 100 | 2 |
| 2016-08-30 | KORIM | 300 | 3 | 2016-08-30 | RATES | 100 | 3 |
| 2016-08-30 | SALEVOUCHR | 400 | 4 | 2016-08-30 | SALARY | 100 | 4 |
| NULL | NULL | NULL | NULL | 2016-08-30 | INSURANCE | 100 | 5 |
+------------+-------------+--------+------+------------+-------------+--------+------+