我有时会遇到父母/子女关系的情况,我想为每个父母选择所有孩子。
这是一个肤浅的例子。
SELECT parent.id as parent_id, child.id as child_id
FROM parent LEFT JOIN child ON parent.id = child.parent_id
ORDER BY parent.id
会产生
parent_id child_id
1 20
1 21
2 33
2 67
我想做点什么
SELECT parent.id, child1.id as child1_id, child2.id as child2_id
FROM parent LEFT JOIN child ON parent.id = child.parent_id
GROUP BY parent.id
并且收益
parent_id child1_id child2_id
1 20 21
2 33 67
我正在尝试避免使用GROUP_CONCAT
因为我想为每个孩子创建单独的列。
我意识到我可以加入孩子两次并过滤选择,但鉴于我的实际数据集,它可能会连续两次加入。而且,如果你可以用任意数量的孩子这样做,那真的很酷:
parent_id child1_id child2_id child3_id
1 20 21 null
2 33 67 109
3 45 null null
答案 0 :(得分:2)
您正在寻找的内容称为PIVOT
。 MySQL不支持PIVOT
命令,但您可以使用MAX
CASE
来模拟它。
如果您知道孩子的数量或者您可以拥有最大数量,这将非常有用。
SELECT parent.id as parent_id,
MAX(CASE WHEN rn = 1 THEN child.id END) child1_id,
MAX(CASE WHEN rn = 2 THEN child.id END) child2_id,
MAX(CASE WHEN rn = 3 THEN child.id END) child3_id,
MAX(CASE WHEN rn = 4 THEN child.id END) child4_id,
MAX(CASE WHEN rn = 5 THEN child.id END) child5_id
FROM parent
LEFT JOIN (
SELECT *,
@rn:=IF(@prevParent=parent_id,@rn+1,1) rn,
@prevParent:=parent_id
FROM child JOIN (SELECT @rn:=0,@prevParent:=0) t
) child ON parent.id = child.parent_id
GROUP BY parent.id
ORDER BY parent.id;
如果您不知道子项/潜在列的数量,则需要考虑创建动态SQL。
以下是一个例子:
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(rn = ', rn, ',child.id,NULL)) AS child_id', rn)
) INTO @sql
FROM parent
LEFT JOIN (
SELECT *,
@rn:=IF(@prevParent=parent_id,@rn+1,1) rn,
@prevParent:=parent_id
FROM child JOIN (SELECT @rn:=0,@prevParent:=0) t
) child ON parent.id = child.parent_id
;
SET @sql = CONCAT('SELECT parent.id as parent_id,
', @sql, '
FROM parent
LEFT JOIN (
SELECT *,
@rn:=IF(@prevParent=parent_id,@rn+1,1) rn,
@prevParent:=parent_id
FROM child JOIN (SELECT @rn:=0,@prevParent:=0) t
) child ON parent.id = child.parent_id
GROUP BY parent.id
ORDER BY parent.id;');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
答案 1 :(得分:1)
您可以在没有变量且没有动态SQL的情况下执行此操作。我们的想法是使用子查询和然后来获取有关列的信息。
让所有孩子:
SELECT parent.id, group_concat(child.id) as children, count(*) as numchildren
FROM parent LEFT JOIN
child ON parent.id = child.parent_id
GROUP BY parent.id
现在使用substring_index()
和reverse()
提取这些内容。这是一个复杂的表达式,它返回列表中的第n个值:
select parent_id,
substring_index(children, ',', 1) as child1,
reverse(substring_index(reverse(substring_index(children, ',', 2)), ',', 1)) as child2,
reverse(substring_index(reverse(substring_index(children, ',', 3)), ',', 1)) as child3,
reverse(substring_index(reverse(substring_index(children, ',', 4)), ',', 1)) as child4
from (SELECT parent.id, group_concat(child.id) as children, count(*) as numchildren
FROM parent LEFT JOIN
child ON parent.id = child.parent_id
GROUP BY parent.id
) t
答案 2 :(得分:0)
您需要动态创建必要的SQ。
您所需查询的SQL需要静态知道要创建的列数以及要使用的列名。通过动态创建SQL查询,然后运行它,您可以实现所需的效果。