如何合并具有不同列数的MySQL查询?

时间:2009-09-27 14:34:52

标签: sql mysql

定义:

  • 在结果中,*表示空列
  • 表中的数据使得表中的每个字段都具有值Fieldname + RowCount(因此第1行中的列'a'包含值'a1')。

2个MySQL表

  • 表1 字段名:a,b,c,d

  • 表2 字段名:e,f,g,h,i,j

任务:

我想从每个表中获取前4行。

独立查询

SELECT Table1.* FROM Table1 WHERE 1 LIMIT 0,4 -- Colcount 4
SELECT Table2.* FROM Table2 WHERE 1 LIMIT 0,4 -- Colcount 6

查询的简单UNION失败,因为这两个部分具有不同的列数。

版本1:向第一个查询添加两个空字段

SELECT Table1.*,'' AS i,'' AS j FROM Table1 WHERE 1 LIMIT 0,4  
UNION 
SELECT Table2.* FROM Table2 WHERE 1 LIMIT 0,4

所以我将在结果集中得到以下字段:

a,b,c,d,i,j

a1,b1,c1,d1,*,*,
a2,b2,c2,d2,*,*,
....
....
e1,f1,g1,h1,i1,j1
e2,f2,g2,h2,i2,j2

问题是Table2的字段名称被Table1覆盖。

版本2 - 使用空字段移动列:

  SELECT Table1.*,'','','','','','' FROM Table1 WHERE 1 LIMIT 0,4  
  UNION 
  SELECT '','','','',Table2.* FROM Table2 WHERE 1 LIMIT 0,4

所以我将在结果集中得到以下字段:

a,b,c,d,i,j

a1,b1,c1,d1,*,*,*,*,*,*,
a2,b2,c2,d2,*,*,*,*,*,*,
....
....
*,*,*,*,e1,f1,g1,h1,i1,j1
*,*,*,*,e2,f2,g2,h2,i2,j2
....
....

问题解决但我得到很多空字段。

是否存在已知的性能问题?

你如何解决这个任务?

是否有解决此问题的最佳做法?

3 个答案:

答案 0 :(得分:4)

查询的输出应该是一个表,它是一组行,每行具有相同的列名和类型集。 (有一些DBMS支持不规则的行 - 具有不同的列集,但这不是主流功能。)

你必须决定如何在两组中处理两组具有不同列数的四行。

最简单的选择通常是执行两个独立查询。这两个结果集不具有可比性,不应混淆。

如果选择版本1,则应确定哪组列名称合适,或使用“AS x”列别名创建一组复合名称。

如果您选择版本2,那么您应该命名UNION第一个子句的尾随列;目前,他们都没有名字:

SELECT Table1.*, '' AS e, '' AS f, '' AS g, '' AS h, '' AS i, '' AS j
  FROM Table1 WHERE 1 LIMIT 0,4  
UNION 
SELECT '' AS a, '' AS b, '' AS c, '' AS d, Table2.*
  FROM Table2 WHERE 1 LIMIT 0,4

(第二个中的AS注释是多余的,但是是自洽的; UNION的两半明确地具有相同的列标题。)

除了您提供空字符串而不是NULL之外,您选择的符号对应于'OUTER UNION'。你可以在文献的选定部分偶尔找到它(E F Codd in the RM / V2 book; C J Date in critiques of all things OUTER)。 SQL 1999将其作为UNION JOIN提供; SQL 2003删除了UNION JOIN(这很不寻常 - 并且该功能受到了谴责)。

我会使用两个单独的查询。

答案 1 :(得分:3)

最明智的是你的“版本2”,除了使用NULL而不是空字符串。

答案 2 :(得分:0)

这需要一些思考,然后是一些特定于MySQL的解决方法。概念是这样的:Join将产生您想要的表结构。您真正想要的是没有行“匹配”的完全外部联接。为此,我们需要一种可靠的方法来确保行不匹配,然后,我们必须使用UNION和LEFT JOIN以及一个RIGHT JOIN,以克服MySQL对FULL OUTER JOIN的限制。

SQL Fiddle

MySQL 5.6模式设置

CREATE TABLE A (a int, b int, c int, d int);
CREATE TABLE B (e int, f int, g int, h int, i int, j int);

INSERT INTO A VALUES (1,1,1,1),(2,2,2,2);
INSERT INTO B VALUES (8,8,8,8,8,8),(9,9,9,9,9,9);

查询1

SELECT * FROM 
(SELECT * FROM (SELECT "TableA" as unique_field) as Ax CROSS JOIN A) as A 
LEFT JOIN
(SELECT * FROM (SELECT "TableB" as unique_field) as Bx CROSS JOIN B) AS B
on A.unique_field=B.unique_field
UNION
SELECT * FROM 
(SELECT * FROM (SELECT "TableA" as unique_field) as Ax CROSS JOIN A) as A 
RIGHT JOIN
(SELECT * FROM (SELECT "TableB" as unique_field) as Bx CROSS JOIN B) AS B
on A.unique_field=B.unique_field

Results

| unique_field |      a |      b |      c |      d | unique_field |      e |      f |      g |      h |      i |      j |
|--------------|--------|--------|--------|--------|--------------|--------|--------|--------|--------|--------|--------|
|       TableA |      1 |      1 |      1 |      1 |       (null) | (null) | (null) | (null) | (null) | (null) | (null) |
|       TableA |      2 |      2 |      2 |      2 |       (null) | (null) | (null) | (null) | (null) | (null) | (null) |
|       (null) | (null) | (null) | (null) | (null) |       TableB |      8 |      8 |      8 |      8 |      8 |      8 |
|       (null) | (null) | (null) | (null) | (null) |       TableB |      9 |      9 |      9 |      9 |      9 |      9 |

此语法:SELECT * FROM (SELECT 1 as unique_field) as Ax CROSS JOIN A) as A更容易理解为(SELECT 1 as unique_field, * FROM A) AS A,但是MySQL不允许*遵循字段规范。