如何一次检索所有 grand parents
How to retrieve all grand parents at once
我在 SQLITE3 中有两个简单的表(家庭关系):
“人”(id、fname、lname)
“关系”(parent/child)
我想得到每个 grand children 以及他们所有的 grand parents(从 1 到 4 个取决于 grand child)这样 1 行结果=
Distinct Grand child, Grand parent 1, Grand parent 2, Grand parent 3, Grand parent 4
感谢 Caius Jard,我已经能够在另一个 star overflow 问题中得到每个 child 和它的大 parent。但是,到目前为止我有:
1 行 = Grand child、1 grand parent(因此最多需要 4 行才能获得 child 的所有 grand parent)。
SELECT c.fname, c.lname, gp.fname, gp.lname
FROM relations p_c
INNER JOIN relationships gp_p ON gp_p.child = p_c.parent
INNER JOIN persons gp ON gp.id = gp_p.parent
INNER JOIN persons c ON c.id = p_c.child
ORDER BY c.id;
我该如何编辑它,以便在一行结果中得到每个大 child 以及所有大 parent?
如果可能,只使用 SELECT (+ count/distinct)、WHERE (+in/exists)、INNER/LEFT JOIN、GROUP BY (+having)、ORDER BY。
我们可以通过称为条件聚合的技术将行变成列:
假设你有一个结果集:
x, y
1, hello
2, goodbye
如果你这样写:
SELECT x,
CASE WHEN x = 1 THEN y END as x1,
CASE WHEN x = 2 THEN y END as x2
FROM ...
你会得到这个:
x, x1, x2
1, hello, NULL
2, NULL, goodbye
一列中只有一个值,其余为空。如果您然后使用例如MAX,丢弃空值:
SELECT
MAX(CASE WHEN x = 1 THEN y END) as x1,
MAX(CASE WHEN x = 2 THEN y END) as x2
FROM ...
你会得到
x1, x2
hello, goodbye
我们不得不删除 x,因为我们不能将它放在那里,否则我们必须将它分组,这将防止行折叠
现在根据您的查询,我们可能必须添加其他信息,因为我们需要一些 CASE WHEN 的信息。您没有表示我们可以在其中任意输入行号。希望 persons
包含性别指示符,因为 4 祖父母是一男两女的结果(所以我们有 MM - 父亲的父亲,MF - 父亲的母亲,FM 和 FF 等)
SELECT ...
FROM relations p_c
INNER JOIN relationships gp_p ON gp_p.child = p_c.parent
INNER JOIN persons gp ON gp.id = gp_p.parent
INNER JOIN persons p ON p.id = p_c.parent
INNER JOIN persons c ON c.id = p_c.child
我们现在可以查询每一层家谱的性别:
SELECT c.name as child,
CASE WHEN gp.gender = 'm' AND p.gender = 'm' THEN gp.name END AS fathersfather,
CASE WHEN gp.gender = 'm' AND p.gender = 'f' THEN gp.name END AS fathersmother,
CASE WHEN gp.gender = 'f' AND p.gender = 'm' THEN gp.name END AS mothersfather,
CASE WHEN gp.gender = 'f' AND p.gender = 'f' THEN gp.name END AS mothersmother
FROM relations p_c
INNER JOIN relationships gp_p ON gp_p.child = p_c.parent
INNER JOIN persons gp ON gp.id = gp_p.parent
INNER JOIN persons p ON p.id = p_c.parent
INNER JOIN persons c ON c.id = p_c.child
这将给出 child 然后是祖父母姓名的对角线数组。您可以按 child 将其压缩为一行:
SELECT c.name as child,
MAX(CASE WHEN gp.gender = 'm' AND p.gender = 'm' THEN gp.name END) AS fathersfather,
MAX(CASE WHEN gp.gender = 'm' AND p.gender = 'f' THEN gp.name END) AS fathersmother,
MAX(CASE WHEN gp.gender = 'f' AND p.gender = 'm' THEN gp.name END) AS mothersfather,
MAX(CASE WHEN gp.gender = 'f' AND p.gender = 'f' THEN gp.name END) AS mothersmother
FROM relations p_c
INNER JOIN relationships gp_p ON gp_p.child = p_c.parent
INNER JOIN persons gp ON gp.id = gp_p.parent
INNER JOIN persons p ON p.id = p_c.parent
INNER JOIN persons c ON c.id = p_c.child
GROUP BY c.name
假设有四个爷爷奶奶,你可以枚举他们并合计:
SELECT fname, lname,
MAX(CASE WHEN seqnum = 1 THEN grandparent_name END) as grandparent_1,
MAX(CASE WHEN seqnum = 2 THEN grandparent_name END) as grandparent_2,
MAX(CASE WHEN seqnum = 3 THEN grandparent_name END) as grandparent_3,
MAX(CASE WHEN seqnum = 4 THEN grandparent_name END) as grandparent_4
FROM (SELECT c.id, c.fname, c.lname,
gp.fname || ' ' || gp.lname as grandparent_name,
ROW_NUMBER() OVER (PARTITION BY c.id ORDER BY gp.fname, gp.lanme) as seqnum
FROM relations p_c JOIN
relationships gp_p
ON gp_p.child = p_c.parent JOIN
persons gp
ON gp.id = gp_p.parent
persons c
ON c.id = p_c.child
) cgp
GROUP BY fname, lname, id;
我建议使用 GROUP_CONCAT()
而不是 4 列的 grand parents 并得到 1 列所有的 grandparents:
SELECT p.fname, p.lname,
GROUP_CONCAT(gp.fname || ' ' || gp.lname, '|')
FROM persons p
INNER JOIN relationships r1 ON r1.child = p.id
INNER JOIN relationships r2 ON r2.child = r1.parent
INNER JOIN persons gp ON r2.parent = gp.id
GROUP BY p.id
代码简单得多。
如果您希望返回所有人员,甚至是没有 grandparents 的人员,请使用 LEFT
联接而不是 INNER
联接。
我在 SQLITE3 中有两个简单的表(家庭关系):
“人”(id、fname、lname)
“关系”(parent/child)
我想得到每个 grand children 以及他们所有的 grand parents(从 1 到 4 个取决于 grand child)这样 1 行结果=
Distinct Grand child, Grand parent 1, Grand parent 2, Grand parent 3, Grand parent 4
感谢 Caius Jard,我已经能够在另一个 star overflow 问题中得到每个 child 和它的大 parent。但是,到目前为止我有:
1 行 = Grand child、1 grand parent(因此最多需要 4 行才能获得 child 的所有 grand parent)。
SELECT c.fname, c.lname, gp.fname, gp.lname
FROM relations p_c
INNER JOIN relationships gp_p ON gp_p.child = p_c.parent
INNER JOIN persons gp ON gp.id = gp_p.parent
INNER JOIN persons c ON c.id = p_c.child
ORDER BY c.id;
我该如何编辑它,以便在一行结果中得到每个大 child 以及所有大 parent?
如果可能,只使用 SELECT (+ count/distinct)、WHERE (+in/exists)、INNER/LEFT JOIN、GROUP BY (+having)、ORDER BY。
我们可以通过称为条件聚合的技术将行变成列:
假设你有一个结果集:
x, y
1, hello
2, goodbye
如果你这样写:
SELECT x,
CASE WHEN x = 1 THEN y END as x1,
CASE WHEN x = 2 THEN y END as x2
FROM ...
你会得到这个:
x, x1, x2
1, hello, NULL
2, NULL, goodbye
一列中只有一个值,其余为空。如果您然后使用例如MAX,丢弃空值:
SELECT
MAX(CASE WHEN x = 1 THEN y END) as x1,
MAX(CASE WHEN x = 2 THEN y END) as x2
FROM ...
你会得到
x1, x2
hello, goodbye
我们不得不删除 x,因为我们不能将它放在那里,否则我们必须将它分组,这将防止行折叠
现在根据您的查询,我们可能必须添加其他信息,因为我们需要一些 CASE WHEN 的信息。您没有表示我们可以在其中任意输入行号。希望 persons
包含性别指示符,因为 4 祖父母是一男两女的结果(所以我们有 MM - 父亲的父亲,MF - 父亲的母亲,FM 和 FF 等)
SELECT ...
FROM relations p_c
INNER JOIN relationships gp_p ON gp_p.child = p_c.parent
INNER JOIN persons gp ON gp.id = gp_p.parent
INNER JOIN persons p ON p.id = p_c.parent
INNER JOIN persons c ON c.id = p_c.child
我们现在可以查询每一层家谱的性别:
SELECT c.name as child,
CASE WHEN gp.gender = 'm' AND p.gender = 'm' THEN gp.name END AS fathersfather,
CASE WHEN gp.gender = 'm' AND p.gender = 'f' THEN gp.name END AS fathersmother,
CASE WHEN gp.gender = 'f' AND p.gender = 'm' THEN gp.name END AS mothersfather,
CASE WHEN gp.gender = 'f' AND p.gender = 'f' THEN gp.name END AS mothersmother
FROM relations p_c
INNER JOIN relationships gp_p ON gp_p.child = p_c.parent
INNER JOIN persons gp ON gp.id = gp_p.parent
INNER JOIN persons p ON p.id = p_c.parent
INNER JOIN persons c ON c.id = p_c.child
这将给出 child 然后是祖父母姓名的对角线数组。您可以按 child 将其压缩为一行:
SELECT c.name as child,
MAX(CASE WHEN gp.gender = 'm' AND p.gender = 'm' THEN gp.name END) AS fathersfather,
MAX(CASE WHEN gp.gender = 'm' AND p.gender = 'f' THEN gp.name END) AS fathersmother,
MAX(CASE WHEN gp.gender = 'f' AND p.gender = 'm' THEN gp.name END) AS mothersfather,
MAX(CASE WHEN gp.gender = 'f' AND p.gender = 'f' THEN gp.name END) AS mothersmother
FROM relations p_c
INNER JOIN relationships gp_p ON gp_p.child = p_c.parent
INNER JOIN persons gp ON gp.id = gp_p.parent
INNER JOIN persons p ON p.id = p_c.parent
INNER JOIN persons c ON c.id = p_c.child
GROUP BY c.name
假设有四个爷爷奶奶,你可以枚举他们并合计:
SELECT fname, lname,
MAX(CASE WHEN seqnum = 1 THEN grandparent_name END) as grandparent_1,
MAX(CASE WHEN seqnum = 2 THEN grandparent_name END) as grandparent_2,
MAX(CASE WHEN seqnum = 3 THEN grandparent_name END) as grandparent_3,
MAX(CASE WHEN seqnum = 4 THEN grandparent_name END) as grandparent_4
FROM (SELECT c.id, c.fname, c.lname,
gp.fname || ' ' || gp.lname as grandparent_name,
ROW_NUMBER() OVER (PARTITION BY c.id ORDER BY gp.fname, gp.lanme) as seqnum
FROM relations p_c JOIN
relationships gp_p
ON gp_p.child = p_c.parent JOIN
persons gp
ON gp.id = gp_p.parent
persons c
ON c.id = p_c.child
) cgp
GROUP BY fname, lname, id;
我建议使用 GROUP_CONCAT()
而不是 4 列的 grand parents 并得到 1 列所有的 grandparents:
SELECT p.fname, p.lname,
GROUP_CONCAT(gp.fname || ' ' || gp.lname, '|')
FROM persons p
INNER JOIN relationships r1 ON r1.child = p.id
INNER JOIN relationships r2 ON r2.child = r1.parent
INNER JOIN persons gp ON r2.parent = gp.id
GROUP BY p.id
代码简单得多。
如果您希望返回所有人员,甚至是没有 grandparents 的人员,请使用 LEFT
联接而不是 INNER
联接。