2

我有 3 个(MYSQL)表,A、B 和 C。

我想做的是这样的:

SELECT * FROM a
LEFT JOIN b ON b.a_id = a.id
LEFT JOIN c on c.a_id = a.id
WHERE a.id = 1;

我在 B 表上有 4 个条目,其中 B.a_id = 1:

B.id | b.a_id
1    | 1
2    | 1
3    | 1
4    | 1

我在 C 表上也有 2 个这样的条目

C.id | C.a_id
10   | 1
11   | 1

返回结果为 8 个:

C.id | B.id
10    | 1
10    | 2
10    | 3
10    | 4
11    | 1
11    | 2
11    | 3
11    | 4

有没有办法让结果不重复相同的 C 和 B 对象,并返回更像这样的东西?

C.id | B.id
10    | 1
11    | 2
NULL  | 3
NULL  | 4

换句话说,我想说“给我所有映射到 A=1 的东西,但不要重复相同的 C 或 B 两次”。在我的实际数据中,我连接了接近 10 个表,并且所有连接表的所有排列,结果通常有数千行长。

这里有一个类似的问题Connecting Multiple Tables in SQL while Limiting Exponential Results,但我想尽可能避免内部选择。我觉得这是对数据库的一种足够普遍的使用,应该有

4

3 回答 3

1

你想要的不是简单的 SQL,你不应该期望它在关系数据库中很容易。

我建议您将所有值放在一个列中,另一列指定它们的来源。这会导致大量union all查询:

select 'b' as which, b.id
from a join b on b.a_id = a.id and a.id = 1
union all
select 'c', c.id
from a join c on c_aid = b.id and a.id = 1
. . .

结果并不完全是您想要的。

如果您真的希望将数据放在单独的列中,那么您需要使用一种技巧来为每一行分配一个行号。然后,您可以按行号聚合结果。像这样的东西:

select rn,
       MAX(case when which = 'b' then id end) as b,
       MAX(case when which = 'b' then id end) as c
from (select 'b' as which, b.id, @rn := @rn + 1 as rn
      from a join b on b.a_id = a.id and a.id = 1 cross join (select @rn := 0) const
      union all
      select 'c', c.id, @rn := @rn + 1 as rn
      from a join c on c_aid = b.id and a.id = 1 cross join (select @rn := 0) const
     ) t
group by rn
于 2013-05-07T15:59:23.933 回答
1

这是使用 SQL 检索数据的基础;它检索完整行中的数据,每行具有相同的列,如该SELECT子句中请求的投影中所定义。每当我遇到这样的 SQL 问题时,对我有帮助的是问自己三个问题:

  1. 我想要的结果行是什么样的?即,他们会有哪些列?
  2. 数据库如何知道如何填充每一列?
  3. 数据库如何知道要返回哪些行?

回答任何给定场景的这些问题有助于我退后一步,看看为什么某个JOINGROUP BY正在给我带来麻烦;通常,这是由于向数据库询问它没有任何概念的东西。

在您的情况下,检索数据行,数据库无法在不为您提供这些行的笛卡尔积的情况下为您提供表 B 中的多行和表 C中的多行。如果您不想要重复数据,则必须SELECT单独发出 s。

回答上述问题时的措辞:每一行都将包含表 A 中的所有数据,并且......嗯......什么?无法将表 B 和 C 中的多行放入任意数量的列中,因此这是行不通的。无法从 B 和 C 返回短行数据,因为每一行的长度相同。它必须为 B 中的每一行和 C 中的每一行返回一整行,这为您提供了您所描述的场景。

于 2013-05-07T16:00:49.527 回答
0

有人可能会使用它,但似乎很容易......

你可以试试以下...

而不是左关节

SELECT * FROM a
LEFT JOIN b ON b.a_id = a.id
LEFT JOIN c on c.a_id = a.id
WHERE a.id = 1;

使用以下内连接

SELECT * FROM a
INNER JOIN b ON b.a_id = a.id
INNER JOIN c on c.a_id = a.id
WHERE a.id = 1;

这应该工作......我想..

于 2013-08-14T15:33:35.850 回答