前言
永远相信美好的事情即将发生
背景
前段时间碰到过这样一个问题,查询出一家店铺在2020年和2019年活动类型为’xxx’的日期,因历史原因,2019年的活动和2020年的活动分别存储在两张表中,需要通过外连接将查询结果放在一起展示,最终要的结果大概长这样:
2019年日期 | 2019年活动 | 2020年日期 | 2020年活动 |
---|---|---|---|
2019/01/05 | xxx节 | 2020/02/01 | xxx节 |
2019/03/12 | xxx节 | 2020/04/10 | xxx节 |
2019/07/19 | xxx节 | 2020/06/05 | xxx节 |
2020/09/09 | xxx节 | ||
2020/12/15 | xxx节 |
踩坑
刚接手需求的时候,我的内心是这样的
我祭出我小学5年级的SQL功底,通过费马定理,泰勒公式,拉格朗日定理以及洛必达法则,再结合我眼花缭乱的一指禅打字技术,终于不负众望的没写出来
问题的原因是什么呢,单独查询2019年活动类型为’xxx’的日期很简单,单独查询2020年活动类型为’xxx’的日期也很简单,那么关联条件呢?肯定会有憨憨说用店铺id关联啊,或者说用活动类型关联啊
左边的查询结果和右边的查询结果已经查询出了这家店铺分别在2020年和2019年活动类型为’xxx’的日期,无论是通过店铺id还是活动类型关联都会做笛卡尔积,所以需要另寻其他关联条件
解决
抱着不耻下问,不对,是不耻上问的学习态度,请教了我们的老大,当时的情景大概是这样
大佬给我指了条明路,行号关联查询,然后亲自指导了一番,在大牛的光辉照耀以及我的不懈努(bai)力(du)下,我终于不负众望的写了出来,SQL简化后大体如下:
SELECT
*
FROM
(
SELECT
@rownuma := @rownuma + 1 AS num_1, table_a.*
FROM table_a,
( SELECT @rownuma := 0 )
) a
LEFT JOIN (
SELECT
@rownumb := @rownumb + 1 AS num_2, table_b.*
FROM table_b,
( SELECT @rownumb := 0 )
) b ON a.num_1 = b.num_2
给左边的查询结果和右边的查询结果分别添加一个行号,行号都是从1开始,这样就可以做到左边的数据集和右边的数据集进行关联,但是
当左边结果集的行数小于等于右边的结果时,这种写法没有任何的问题,那么当右边的结果集行数大于左边呢,没错,它只能显示和左边行数一样的部分,那么问题来了,当左右结果集行数不确定的时候怎么办呢?没错,使用union连接一下左外连接和右外连接的结果集就o的k了
SELECT
*
FROM
(
SELECT
@rownuma := @rownuma + 1 AS num_1, table_a.*
FROM table_a,
( SELECT @rownuma := 0 )
) a
LEFT JOIN (
SELECT
@rownumb := @rownumb + 1 AS num_2, table_b.*
FROM table_b,
( SELECT @rownumb := 0 )
) b ON a.num_1 = b.num_2
UNION
SELECT
*
FROM
(
SELECT
@rownumc := @rownumc + 1 AS num_1, table_a.*
FROM table_a,
( SELECT @rownumc := 0 )
) a
RIGHT JOIN (
SELECT
@rownumd := @rownumd + 1 AS num_2, table_b.*
FROM table_b,
( SELECT @rownumd := 0 )
) b ON a.num_1 = b.num_2
注意点
使用行号名的时候切记不要使用相同的名称,应该像这样
如果使用了相同的名称,你会发现关联之后的结果集某一列一开始会有很多的空白,别问我为什么知道,以前有一个憨憨就这样被坑了半天还不知道原因
总结
实际开发中碰到这种类似无规则关联的情景其实也比较少,但由于MySQL中缺少很多SQL关联的方法,就导致需要想点其他的方法去解决,希望各位看了我的踩坑之旅后能少踩点雷。
与诸君共勉