MYSQL 左联接不包括现有行
MYSQL left join include not existing rows
我目前已经创建了以下极其简化的 mysql table 来模仿我当前的 tables。
晋级 table:
CREATE TABLE promotion (
promotion Varchar NOT NULL,
PRIMARY KEY (promotion)
);
sale_id
10%
20%
30%
和销售 table:
CREATE TABLE sale (
sale_id int NOT NULL AUTO_INCREMENT,
promotion Varchar,
date Date NOT NULL,
amount int,
PRIMARY KEY (sale_id)
);
sale_id
promotion
date
amount
1
null
2022-1-1
100
2
10%
2022-1-1
100
3
10%
2022-1-1
100
4
20%
2022-1-1
100
5
null
2022-1-2
100
6
10%
2022-1-2
100
7
30%
2022-1-2
100
8
30%
2022-1-2
100
其中 promotion_id 是升级 table 的外键。所以关系是每次销售可以没有促销(null)或促销(促销主键的int id值作为外键)。
我正在尝试按月显示数据,然后按促销显示数据,其中每个月都有一堆按促销分组的销售金额总计。
到目前为止我有这个查询:
select
Month(date),
ifnull(promotion,'No Promo'),
sum(amount)
from sale
left join promotion p on p.promotion = sale.promotion
group by Month(date), sale.promotion
这给了我以下结果:
month
promotion
amount
1
null
100
1
10%
200
1
20%
100
2
null
100
2
10%
100
2
30%
200
但我想要的是:
month
promotion
amount
1
null
100
1
10%
200
1
20%
100
1
30%
0
2
null
100
2
10%
100
2
20%
0
2
30%
200
右加入不是意味着将促销列表中的每个促销都包含在促销 table 中吗?不管那个月是否有促销活动?
谁能给我一些正确方向的提示,说明为什么我的右连接不起作用?
您需要在联接中反转表的顺序。 (右连接也可以,但并非所有版本都支持)
select
Month(date),
ifnull(promotion,'No Promo'),
sum(amount)
from promotion p
left join sale on p.promotion = sale.promotion
group by Month(date), ifnull(promotion,'No Promo');
我稍微修改了你的查询和你的 table 定义,它在 dbFiddle 中工作正常。
CREATE TABLE promotion (
promotion Varchar(4) NOT NULL
PRIMARY KEY
);
✓
INSERT INTO promotion VALUES ('10%'),('20%'),('30%');
✓
CREATE TABLE sale (
sale_id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
promotion Varchar(4),
date_ Date NOT NULL,
amount int
);
✓
insert into sale (promotion, date_, amount) values
(null,'2022-1-1',100),
('10%','2022-1-1',100),
('20%','2022-1-1',100),
('30%','2022-1-1',100),
(null,'2022-1-2',100),
('10%','2022-1-2',110),
('20%','2022-1-2',120),
('30%','2022-1-2',130),
(null,'2022-2-1',75),
('10%','2022-2-1',75),
('20%','2022-2-1',75),
('30%','2022-2-1',75),
(null,'2022-2-2',75),
('10%','2022-2-2',75),
('20%','2022-2-2',75),
('30%','2022-2-2',75);
✓
select
Month(date_) month_,
ifnull(p.promotion,'No Promo') Promotion,
sum(amount) Total
from sale
left join promotion p on p.promotion = sale.promotion
group by Month(date_), ifnull(p.promotion,'No Promo');
month_ | Promotion | Total
-----: | :-------- | ----:
1 | No Promo | 200
1 | 10% | 210
1 | 20% | 220
1 | 30% | 230
2 | No Promo | 150
2 | 10% | 150
2 | 20% | 150
2 | 30% | 150
db<>fiddle here
我们需要将升级中的约束从主键更改为唯一以允许空值。然后,我们可以使用交叉连接创建所有行,然后左连接到 sale 以检索已售商品的价值。
CREATE TABLE promotion (
promotion Varchar(4)
UNIQUE
);
✓
INSERT INTO promotion VALUES (null),('10%'),('20%'),('30%');
✓
CREATE TABLE sale (
sale_id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
promotion Varchar(4),
date_ Date NOT NULL,
amount int
);
✓
insert into sale (promotion, date_, amount) values
(null,'2022-1-1',100),
('10%','2022-1-1',100),
('20%','2022-1-1',100),
('30%','2022-1-1',100),
(null,'2022-1-2',100),
('10%','2022-1-2',110),
('20%','2022-1-2',120),
('30%','2022-1-2',130),
(null,'2022-2-1',75),
('10%','2022-2-1',75),
('30%','2022-2-1',75),
(null,'2022-2-2',75),
('10%','2022-2-2',75),
('30%','2022-2-2',75);
✓
select
Month(date_) month_,
ifnull(p.promotion,'No Promo') Promotion,
sum(amount) Total
from sale
left join promotion p on p.promotion = sale.promotion
group by Month(date_), ifnull(p.promotion,'No Promo');
month_ | Promotion | Total
-----: | :-------- | ----:
1 | No Promo | 200
1 | 10% | 210
1 | 20% | 220
1 | 30% | 230
2 | No Promo | 150
2 | 10% | 150
2 | 30% | 150
select
m,
ifnull(p.promotion,'No Promo') Promotion,
sum(amount) Total
from (select distinct month(date_) m from sale) m
cross join
promotion p
left join sale s on m.m = month(date_) and p.promotion = s.promotion
group by m, ifnull(p.promotion,'No Promo')
order by m, ifnull(p.promotion,'No Promo');;
m | Promotion | Total
-: | :-------- | ----:
1 | 10% | 210
1 | 20% | 220
1 | 30% | 230
1 | No Promo | null
2 | 10% | 150
2 | 20% | null
2 | 30% | 150
2 | No Promo | null
db<>fiddle here
我目前已经创建了以下极其简化的 mysql table 来模仿我当前的 tables。
晋级 table:
CREATE TABLE promotion (
promotion Varchar NOT NULL,
PRIMARY KEY (promotion)
);
sale_id |
---|
10% |
20% |
30% |
和销售 table:
CREATE TABLE sale (
sale_id int NOT NULL AUTO_INCREMENT,
promotion Varchar,
date Date NOT NULL,
amount int,
PRIMARY KEY (sale_id)
);
sale_id | promotion | date | amount |
---|---|---|---|
1 | null | 2022-1-1 | 100 |
2 | 10% | 2022-1-1 | 100 |
3 | 10% | 2022-1-1 | 100 |
4 | 20% | 2022-1-1 | 100 |
5 | null | 2022-1-2 | 100 |
6 | 10% | 2022-1-2 | 100 |
7 | 30% | 2022-1-2 | 100 |
8 | 30% | 2022-1-2 | 100 |
其中 promotion_id 是升级 table 的外键。所以关系是每次销售可以没有促销(null)或促销(促销主键的int id值作为外键)。
我正在尝试按月显示数据,然后按促销显示数据,其中每个月都有一堆按促销分组的销售金额总计。
到目前为止我有这个查询:
select
Month(date),
ifnull(promotion,'No Promo'),
sum(amount)
from sale
left join promotion p on p.promotion = sale.promotion
group by Month(date), sale.promotion
这给了我以下结果:
month | promotion | amount |
---|---|---|
1 | null | 100 |
1 | 10% | 200 |
1 | 20% | 100 |
2 | null | 100 |
2 | 10% | 100 |
2 | 30% | 200 |
但我想要的是:
month | promotion | amount |
---|---|---|
1 | null | 100 |
1 | 10% | 200 |
1 | 20% | 100 |
1 | 30% | 0 |
2 | null | 100 |
2 | 10% | 100 |
2 | 20% | 0 |
2 | 30% | 200 |
右加入不是意味着将促销列表中的每个促销都包含在促销 table 中吗?不管那个月是否有促销活动? 谁能给我一些正确方向的提示,说明为什么我的右连接不起作用?
您需要在联接中反转表的顺序。 (右连接也可以,但并非所有版本都支持)
select
Month(date),
ifnull(promotion,'No Promo'),
sum(amount)
from promotion p
left join sale on p.promotion = sale.promotion
group by Month(date), ifnull(promotion,'No Promo');
我稍微修改了你的查询和你的 table 定义,它在 dbFiddle 中工作正常。
CREATE TABLE promotion ( promotion Varchar(4) NOT NULL PRIMARY KEY );
✓
INSERT INTO promotion VALUES ('10%'),('20%'),('30%');
✓
CREATE TABLE sale ( sale_id int NOT NULL PRIMARY KEY AUTO_INCREMENT, promotion Varchar(4), date_ Date NOT NULL, amount int );
✓
insert into sale (promotion, date_, amount) values (null,'2022-1-1',100), ('10%','2022-1-1',100), ('20%','2022-1-1',100), ('30%','2022-1-1',100), (null,'2022-1-2',100), ('10%','2022-1-2',110), ('20%','2022-1-2',120), ('30%','2022-1-2',130), (null,'2022-2-1',75), ('10%','2022-2-1',75), ('20%','2022-2-1',75), ('30%','2022-2-1',75), (null,'2022-2-2',75), ('10%','2022-2-2',75), ('20%','2022-2-2',75), ('30%','2022-2-2',75);
✓
select Month(date_) month_, ifnull(p.promotion,'No Promo') Promotion, sum(amount) Total from sale left join promotion p on p.promotion = sale.promotion group by Month(date_), ifnull(p.promotion,'No Promo');
month_ | Promotion | Total -----: | :-------- | ----: 1 | No Promo | 200 1 | 10% | 210 1 | 20% | 220 1 | 30% | 230 2 | No Promo | 150 2 | 10% | 150 2 | 20% | 150 2 | 30% | 150
db<>fiddle here
我们需要将升级中的约束从主键更改为唯一以允许空值。然后,我们可以使用交叉连接创建所有行,然后左连接到 sale 以检索已售商品的价值。
CREATE TABLE promotion ( promotion Varchar(4) UNIQUE );
✓
INSERT INTO promotion VALUES (null),('10%'),('20%'),('30%');
✓
CREATE TABLE sale ( sale_id int NOT NULL PRIMARY KEY AUTO_INCREMENT, promotion Varchar(4), date_ Date NOT NULL, amount int );
✓
insert into sale (promotion, date_, amount) values (null,'2022-1-1',100), ('10%','2022-1-1',100), ('20%','2022-1-1',100), ('30%','2022-1-1',100), (null,'2022-1-2',100), ('10%','2022-1-2',110), ('20%','2022-1-2',120), ('30%','2022-1-2',130), (null,'2022-2-1',75), ('10%','2022-2-1',75), ('30%','2022-2-1',75), (null,'2022-2-2',75), ('10%','2022-2-2',75), ('30%','2022-2-2',75);
✓
select Month(date_) month_, ifnull(p.promotion,'No Promo') Promotion, sum(amount) Total from sale left join promotion p on p.promotion = sale.promotion group by Month(date_), ifnull(p.promotion,'No Promo');
month_ | Promotion | Total -----: | :-------- | ----: 1 | No Promo | 200 1 | 10% | 210 1 | 20% | 220 1 | 30% | 230 2 | No Promo | 150 2 | 10% | 150 2 | 30% | 150
select m, ifnull(p.promotion,'No Promo') Promotion, sum(amount) Total from (select distinct month(date_) m from sale) m cross join promotion p left join sale s on m.m = month(date_) and p.promotion = s.promotion group by m, ifnull(p.promotion,'No Promo') order by m, ifnull(p.promotion,'No Promo');;
m | Promotion | Total -: | :-------- | ----: 1 | 10% | 210 1 | 20% | 220 1 | 30% | 230 1 | No Promo | null 2 | 10% | 150 2 | 20% | null 2 | 30% | 150 2 | No Promo | null
db<>fiddle here