从 MySQL 中的左连接中排除一些组合

Excluding some combinations from left join in MySQL

我正在分析游戏数据。我的数据包括游戏 ID (GID)、玩家 ID (PID) 和时间片 (T),.... Table A 和 B 是我的查询创建的两个表,如下所示:

Table A
GID, PID, T, command_freq, command_id
1,   1,   0, 17, 10
1,   1,   0, 4, 5
1,   1,   1, 26, 10
1,   1,   1, 6, 5
1,   1,   2, 5, 5
1,   1,   2, 3, 10
1,   1,   5, 7, 10

Table B
GID, PID, T, order_freq, order_id
 1,  1,   0, 7, 40
 1,  1,   2, 3, 40
 1,  1,   2, 11, 42
 1,  1,   5, 1, 40

我需要找到在每个时间片中完成了哪些命令和命令(还有它们的计数)。结果应该如下:

GID, PID, T, command_count, command_id, order_count, order_id
1,   1,   0,  17,           10,            Null, Null
1,   1,   0,  4,            5 ,            Null, Null
1,   1,   0,  Null,         Null,          7, 40
1,   1,   1,  26,           10,            Null, Null
1,   1,   1,  6,            5,             Null, Null
1,   1,   2,  5,            5,             Null, Null
1,   1,   2,  3,            10,            Null, Null
1,   1,   2,  Null,         Null,          3, 40
1,   1,   2,  Null,         Null,          11, 42
1,   1,   5,  7,            10,            Null, Null
1,   1,   5,  Null,         Null,          1, 40

通常在 T=t 中我们可以有 0 到 n 个命令或命令。我需要 T=t.

的所有命令和命令的联合
declare @A table (gid int,pid int,t int,f1 int, f2 int)
insert into @a values
(1,   1,   0, 17, 10),
(1,   1,   0, 4, 5),
(1,   1,   1, 26, 10),
(1,   1,   1, 6, 5),
(1,   1,   2, 5, 5),
(1,   1,   2, 3, 10),
(1,   1,   5, 7, 10),
(1,   1,   6, 3, 7),
(1,   1,   6, 8, 5)

declare @b table (gid int,pid int,t int,f3 int,f4 int)
insert into @b
values
( 1,  1,   0, 7, 40),
( 1,  1,   2, 3, 40),
( 1,  1,   5, 1, 40)


select  a.gid,a.pid,a.t,a.f1,a.f2,b.f3,b.f4 
from    @a a
join    @b b on b.gid = a.gid and b.pid = a.pid and b.t = a.t
where   a.t <> 0
union
select  a.gid,a.pid,a.t,a.f1,a.f2,null,null
from    @a a
where   a.t = 0
union
select  b.gid,b.pid,b.t,null,null,b.f3,b.f4
from    @b b
where   b.t = 0

架构

drop table if exists ta;
create table ta (GID int,PID int,T int,command_freq int, command_id int);
insert into ta values
(1,   1,   0, 17, 10),
(1,   1,   0, 4, 5),
(1,   1,   1, 26, 10),
(1,   1,   1, 6, 5),
(1,   1,   2, 5, 5),
(1,   1,   2, 3, 10),
(1,   1,   5, 7, 10);

drop table if exists tb;
create table tb (gid int,pid int,t int,order_freq int,order_id int);
insert into tb values
( 1,  1,   0, 7, 40),
( 1,  1,   2, 3, 40),
( 1,  1,   2, 11, 42),
( 1,  1,   5, 1, 40);

请注意,使用联合时,联合中的第一个查询会驱动最终输出的列名目标:

GID, PID, T, command_count, command_id, order_count, order_id

因此,如果他们愿意,联合中的第二次和之后的查询可以草率地处理它,至少在他们所谓的列名方面是这样。

下面的第一个查询,虽然它生成了 same 输出,至少通过命令行实用程序输出显示给你 here,提供如果我 运行 通过 MySQL Workbench.

结果与第二个查询略有不同
select GID,PID,T,command_count,command_id,order_count,order_id 
from 
(   select GID, PID, T, command_freq as command_count, command_id, null as order_count, null as order_id, 1 as theOrder from ta 
    union  
    select GID, PID, T, null as command_count, null, order_freq as order_count, order_id, 2 as theOrder from tb 
) xDerived 
order by GID,PID,T,theOrder; 
+------+------+------+---------------+------------+-------------+----------+
| GID  | PID  | T    | command_count | command_id | order_count | order_id |
+------+------+------+---------------+------------+-------------+----------+
|    1 |    1 |    0 |            17 |         10 |        NULL |     NULL |
|    1 |    1 |    0 |             4 |          5 |        NULL |     NULL |
|    1 |    1 |    0 |          NULL |       NULL |           7 |       40 |
|    1 |    1 |    1 |            26 |         10 |        NULL |     NULL |
|    1 |    1 |    1 |             6 |          5 |        NULL |     NULL |
|    1 |    1 |    2 |             5 |          5 |        NULL |     NULL |
|    1 |    1 |    2 |             3 |         10 |        NULL |     NULL |
|    1 |    1 |    2 |          NULL |       NULL |          11 |       42 |
|    1 |    1 |    2 |          NULL |       NULL |           3 |       40 |
|    1 |    1 |    5 |             7 |         10 |        NULL |     NULL |
|    1 |    1 |    5 |          NULL |       NULL |           1 |       40 |
+------+------+------+---------------+------------+-------------+----------+
11 rows in set (0.00 sec)

如果这在 GID,PID,T 块中甚至很重要,下面的第二个版本需要额外的努力来使用 rownum 来命中你的结果排序。第二个结果集至少通过 mysql 命令行工具和 MySQL Workbench:

为我显示相同的顺序
select GID,PID,T,command_count,command_id,order_count,order_id 
from 
(   select GID, PID, T, command_freq as command_count, command_id, null as order_count, null as order_id, 1 as theOrder,@rn1:=@rn1+1 as rownum 
    from ta 
    cross join (select @rn1:=0) xParams1 
    union  
    select GID, PID, T, null as command_count, null, order_freq as order_count, order_id, 2 as theOrder,@rn2:=@rn2+1 as rownum   from tb 
    cross join (select @rn2:=0) xParams2 
) xDerived 
order by GID,PID,T,theOrder,rownum; 
+------+------+------+---------------+------------+-------------+----------+
| GID  | PID  | T    | command_count | command_id | order_count | order_id |
+------+------+------+---------------+------------+-------------+----------+
|    1 |    1 |    0 |            17 |         10 |        NULL |     NULL |
|    1 |    1 |    0 |             4 |          5 |        NULL |     NULL |
|    1 |    1 |    0 |          NULL |       NULL |           7 |       40 |
|    1 |    1 |    1 |            26 |         10 |        NULL |     NULL |
|    1 |    1 |    1 |             6 |          5 |        NULL |     NULL |
|    1 |    1 |    2 |             5 |          5 |        NULL |     NULL |
|    1 |    1 |    2 |             3 |         10 |        NULL |     NULL |
|    1 |    1 |    2 |          NULL |       NULL |           3 |       40 |
|    1 |    1 |    2 |          NULL |       NULL |          11 |       42 |
|    1 |    1 |    5 |             7 |         10 |        NULL |     NULL |
|    1 |    1 |    5 |          NULL |       NULL |           1 |       40 |
+------+------+------+---------------+------------+-------------+----------+
11 rows in set (0.00 sec)

在任何一种情况下,theOrder 列都用于强制 NULL 的输出位于每个 GID,PID,T 块的底部。

我介绍它们是为了让您可视化变量的使用和排序,以便在您进行更改时达到所需的输出排序。