我想创建动态的虚拟列,其中的值是基于连接表生成的。
我有下表叫做类型:
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中做吗?
答案 0 :(得分:3)
我在这里概述了几个案例。
首先,最直截了当的是:
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';
但这需要手动提及查询中的所有类型,这显然不是您所寻求的。
可以构建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(或其他)脚本应该很容易。
在标准SQL中,无法使用表的内容来创建DML语句。不同的数据库为此提供了不同的功能,如PIVOT
语句,过程语言等。我不知道如何使用MySQL工具实现这一点,但我们的想法是动态构建第2点中概述的查询并执行它
我已经介绍了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
有四种不同的类型,但a
和b
只有一种与之关联的类型。
如果你事先知道要检查的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