SQL连接多个表而不返回相同的连接ID两次

时间:2013-05-07 15:51:37

标签: mysql sql join

我有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,但我希望尽可能避免内部选择。我觉得这是应该有

的数据库的常见用法

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

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

  1. 我想要的结果行是什么样的?即,他们会有哪些专栏?
  2. 数据库如何知道如何填充每列?
  3. 数据库将如何知道要返回哪些行?
  4. 为任何特定情况回答这些问题有助于我退后一步,看看为什么某个JOINGROUP BY会给我带来麻烦;一般来说,这是因为要求数据库提供一些它没有任何概念的东西。

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

    回答上述问题:每一行都有表A中的所有数据,而且......呃......什么?无法将表B和C中的多行放入任意数量的列中,因此无效。没有办法从B和C返回短行数据,因为每行的长度相同。它必须为B中的每一行和C中的每一行返回一个完整的行,这将为您提供您描述的场景。

答案 2 :(得分: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;

那应该有用......我想..