从mysql中的表创建动态创建的列

时间:2012-07-01 07:26:22

标签: mysql

我想创建动态的虚拟列,其中的值是基于连接表生成的。

我有下表叫做类型:

id, name
1, TypeA
2, TypeB

我有一个名为category

的表
id, name, type
1, a, 1
2, b, 2

我想要一个返回以下内容的查询

category name, TypeA, TypeB
a, 1, 0
b, 0, 1

这可以在mysql中做吗?

2 个答案:

答案 0 :(得分:3)

我在这里概述了几个案例。

  1. 首先,最直截了当的是:

    SELECT c.name AS "CatName",
           IF(typea.id IS NULL, 0, 1) AS "TypeA",
           IF(typeb.id IS NULL, 0, 1) AS "TypeB"
      FROM category c
      LEFT JOIN types typea ON c.type = typea.id AND typea.name = 'TypeA'
      LEFT JOIN types typeb ON c.type = typeb.id AND typeb.name = 'TypeB';
    

    但这需要手动提及查询中的所有类型,这显然不是您所寻求的。

  2. 可以构建SQL查询并使用它,此方法假设您正在运行来自某个脚本的查询,该脚本可以从第一个查询中获取输出并将其用作新查询。

    SELECT concat('SELECT c.name AS "CatName",',
        group_concat(concat('IF(',lower(t.name),
          '.id IS NULL,0,1) AS "',t.name,'"')),
        ' FROM category c ',
        group_concat(concat('LEFT JOIN types ',
          lower(t.name),' ON c.type = ',lower(t.name),'.id AND ',
          lower(t.name),'.name = ''',t.name,'''') SEPARATOR ' '),
        ';')
      FROM types t;
    

    编写一个小shell(或其他)脚本应该很容易。

  3. 在标准SQL中,无法使用表的内容来创建DML语句。不同的数据库为此提供了不同的功能,如PIVOT语句,过程语言等。我不知道如何使用MySQL工具实现这一点,但我们的想法是动态构建第2点中概述的查询并执行它

  4. 我已经介绍了SQL Fiddle上的前两个案例。

答案 1 :(得分:1)

有一个名为PIVOT的功能可以满足您的需求,但不幸的是,它在MySQL中不可用。

所做的是将每个类别的所有类型连接成一个字符串:

SELECT
    a.name,
    GROUP_CONCAT(b.name) AS types
FROM
    category a
LEFT JOIN
    types b ON a.type = b.id
GROUP BY
    a.id

这会产生类似的结果:

name    |    types
--------------------------------
a       |    TypeA
b       |    TypeB
c       |    TypeA,TypeB,TypeC,TypeD

类别c有四种不同的类型,但ab只有一种与之关联的类型。

如果你事先知道要检查的type是什么和多少,并且想要显示一个布尔值,如果该类别存在该类型,你可以这样做:

SELECT,
    a.name,
    b.id IS NOT NULL AS TypeA,
    c.id IS NOT NULL AS TypeB,
    -- etc...
FROM
    category a
LEFT JOIN
    types b ON a.type = b.id AND b.id = 1
LEFT JOIN
    types c ON a.type = c.id AND c.id = 2
-- etc...

编辑:如果您不知道预先要创建的列数,但仍希望每个类型的布尔值位于各自的列中,则另一个选项是动态在应用程序逻辑中构建查询字符串。假设您使用的是PHP,例如:

$columns = $ljoins = array();
$i = 1;

foreach($pdo->query('SELECT id, name FROM types') as $row)
{
    $columns[] = "t$i.id IS NOT NULL AS " . $row['name'];
    $ljoins[] = "LEFT JOIN types t$i ON a.type = t$i.id AND t$i.id = " . $row['id'];
    $i++;
}

$sql = 'SELECT a.name, ' . implode(', ', $columns) . ' FROM category a ' . implode(' ', $ljoins);
$stmt = $pdo->query($sql);

// Do stuff with result-set