当 child 个数学条件时选择 parent 个记录
Selecting parent records when child mathes criteria
我试图将用户的 returned 结果限制为 "recent" 但用户有 parent 的结果,我还需要 return parent.
CREATE TABLE `users` (
`id` int(0) NOT NULL,
`parent_id` int(0) NULL,
`name` varchar(255) NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `times` (
`id` int(11) NOT NULL,
`time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO `users`(`id`, `parent_id`, `name`) VALUES (1, NULL, 'Alan');
INSERT INTO `users`(`id`, `parent_id`, `name`) VALUES (2, 1, 'John');
INSERT INTO `users`(`id`, `parent_id`, `name`) VALUES (3, NULL, 'Jerry');
INSERT INTO `users`(`id`, `parent_id`, `name`) VALUES (4, NULL, 'Bill');
INSERT INTO `users`(`id`, `parent_id`, `name`) VALUES (5, 1, 'Carl');
INSERT INTO `times`(`id`, `time`) VALUES (2, '2019-01-01 14:40:38');
INSERT INTO `times`(`id`, `time`) VALUES (4, '2019-01-01 14:40:38');
http://sqlfiddle.com/#!9/91db19
在这种情况下,我想 return Alan、John 和 Bill,而不是 Jerry,因为 Jerry 在 times
table 中没有记录,他也没有a parent 有记录的人。我对如何处理 Carl 持观望态度,我不介意为他获取结果,但我不需要它们。
我正在筛选具有数十万条 times
记录的数万用户,因此性能很重要。一般来说,我有大约 3000 个来自 times
的唯一 ID,它们可以是 id
,也可以是 parent_id
.
上面是我正在尝试做的一个精简的例子,完整的例子包括更多的连接和案例语句,但一般来说上面的例子应该是我们使用的,但这里是我正在使用的查询(完整查询将近 100 行):
SELECT id AS reference_id,
CASE WHEN (id != parent_id)
THEN
parent_id
ELSE null END AS parent_id,
parent_id AS family_id,
Rtrim(last_name) AS last_name,
Rtrim(first_name) AS first_name,
Rtrim(email) AS email,
missedappt AS appointment_missed,
appttotal AS appointment_total,
To_char(birth_date, 'YYYY-MM-DD 00:00:00') AS birthday,
To_char(first_visit_date, 'YYYY-MM-DD 00:00:00') AS first_visit,
billing_0_30
FROM users AS p
RIGHT JOIN(
SELECT p.id,
s.parentid,
Count(p.id) AS appttotal,
missedappt,
billing0to30 AS billing_0_30
FROM times AS p
JOIN (SELECT missedappt, parent_id, id
FROM users) AS s
ON p.id = s.id
LEFT JOIN (SELECT parent_id, billing0to30
FROM aging) AS aging
ON aging.parent_id = p.id
WHERE p.apptdate > To_char(Timestampadd(sql_tsi_year, -1, Now()), 'YYYY-MM-DD')
GROUP BY p.id,
s.parent_id,
missedappt,
billing0to30
) AS recent ON recent.patid = p.patient_id
此示例适用于 Faircom C-Tree 数据库,但我还需要在 Sybase、MySql 和 Pervasive 中实施类似的解决方案,所以我只是想了解我应该怎么做才能最好性能。
基本上我需要做的是以某种方式让 RIGHT JOIN
也包括用户 parent.
备注:
基于您的 fiddle 配置,我假设您使用的是 MySQL 5.6,因此不支持通用 Table 表达式(CTE )
我假设每个名字(child 或 parent)在最终结果集中作为单独的记录呈现
我们想限制必须加入 times
和 users
table 的次数(CTE 会使 code/read 更容易一些).
主查询(times -> users(u1) -> users(u2))将在单独的列中为我们提供 child 和 parent 名称,因此我们将使用 2 行动态 table 加上一个 case
语句将列旋转到它们自己的行中(注意:我不使用 MySQL 并且没有时间研究是否有 pivot
能力 MySQL 5.6)
-- we'll let 'distinct' filter out any duplicates (eg, 2 'children' have same 'parent')
select distinct
final.name
from
-- cartesian product of 'allnames' and 'pass' will give us
-- duplicate lines of id/parent_id/child_name/parent_name so
-- we'll use a 'case' statement to determine which name to display
(select case when pass.pass_no = 1
then allnames.child_name
else allnames.parent_name
end as name
from
-- times join users left join users; gives us pairs of
-- child_name/parent_name or child_name/NULL
(select u1.id,u1.parent_id,u1.name as child_name,u2.name as parent_name
from times t
join users u1
on u1.id = t.id
left
join users u2
on u2.id = u1.parent_id) allnames
join
-- poor man's pivot code:
-- 2-row dynamic table; no join clause w/ allnames will give us a
-- cartesian product; the 'case' statement will determine which
-- name (child vs parent) to display
(select 1 as pass_no
union
select 2) pass
) final
-- eliminate 'NULL' as a name in our final result set
where final.name is not NULL
order by 1
结果集:
name
==============
Alan
Bill
John
我试图将用户的 returned 结果限制为 "recent" 但用户有 parent 的结果,我还需要 return parent.
CREATE TABLE `users` (
`id` int(0) NOT NULL,
`parent_id` int(0) NULL,
`name` varchar(255) NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `times` (
`id` int(11) NOT NULL,
`time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO `users`(`id`, `parent_id`, `name`) VALUES (1, NULL, 'Alan');
INSERT INTO `users`(`id`, `parent_id`, `name`) VALUES (2, 1, 'John');
INSERT INTO `users`(`id`, `parent_id`, `name`) VALUES (3, NULL, 'Jerry');
INSERT INTO `users`(`id`, `parent_id`, `name`) VALUES (4, NULL, 'Bill');
INSERT INTO `users`(`id`, `parent_id`, `name`) VALUES (5, 1, 'Carl');
INSERT INTO `times`(`id`, `time`) VALUES (2, '2019-01-01 14:40:38');
INSERT INTO `times`(`id`, `time`) VALUES (4, '2019-01-01 14:40:38');
http://sqlfiddle.com/#!9/91db19
在这种情况下,我想 return Alan、John 和 Bill,而不是 Jerry,因为 Jerry 在 times
table 中没有记录,他也没有a parent 有记录的人。我对如何处理 Carl 持观望态度,我不介意为他获取结果,但我不需要它们。
我正在筛选具有数十万条 times
记录的数万用户,因此性能很重要。一般来说,我有大约 3000 个来自 times
的唯一 ID,它们可以是 id
,也可以是 parent_id
.
上面是我正在尝试做的一个精简的例子,完整的例子包括更多的连接和案例语句,但一般来说上面的例子应该是我们使用的,但这里是我正在使用的查询(完整查询将近 100 行):
SELECT id AS reference_id,
CASE WHEN (id != parent_id)
THEN
parent_id
ELSE null END AS parent_id,
parent_id AS family_id,
Rtrim(last_name) AS last_name,
Rtrim(first_name) AS first_name,
Rtrim(email) AS email,
missedappt AS appointment_missed,
appttotal AS appointment_total,
To_char(birth_date, 'YYYY-MM-DD 00:00:00') AS birthday,
To_char(first_visit_date, 'YYYY-MM-DD 00:00:00') AS first_visit,
billing_0_30
FROM users AS p
RIGHT JOIN(
SELECT p.id,
s.parentid,
Count(p.id) AS appttotal,
missedappt,
billing0to30 AS billing_0_30
FROM times AS p
JOIN (SELECT missedappt, parent_id, id
FROM users) AS s
ON p.id = s.id
LEFT JOIN (SELECT parent_id, billing0to30
FROM aging) AS aging
ON aging.parent_id = p.id
WHERE p.apptdate > To_char(Timestampadd(sql_tsi_year, -1, Now()), 'YYYY-MM-DD')
GROUP BY p.id,
s.parent_id,
missedappt,
billing0to30
) AS recent ON recent.patid = p.patient_id
此示例适用于 Faircom C-Tree 数据库,但我还需要在 Sybase、MySql 和 Pervasive 中实施类似的解决方案,所以我只是想了解我应该怎么做才能最好性能。
基本上我需要做的是以某种方式让 RIGHT JOIN
也包括用户 parent.
备注:
基于您的 fiddle 配置,我假设您使用的是 MySQL 5.6,因此不支持通用 Table 表达式(CTE )
我假设每个名字(child 或 parent)在最终结果集中作为单独的记录呈现
我们想限制必须加入 times
和 users
table 的次数(CTE 会使 code/read 更容易一些).
主查询(times -> users(u1) -> users(u2))将在单独的列中为我们提供 child 和 parent 名称,因此我们将使用 2 行动态 table 加上一个 case
语句将列旋转到它们自己的行中(注意:我不使用 MySQL 并且没有时间研究是否有 pivot
能力 MySQL 5.6)
-- we'll let 'distinct' filter out any duplicates (eg, 2 'children' have same 'parent')
select distinct
final.name
from
-- cartesian product of 'allnames' and 'pass' will give us
-- duplicate lines of id/parent_id/child_name/parent_name so
-- we'll use a 'case' statement to determine which name to display
(select case when pass.pass_no = 1
then allnames.child_name
else allnames.parent_name
end as name
from
-- times join users left join users; gives us pairs of
-- child_name/parent_name or child_name/NULL
(select u1.id,u1.parent_id,u1.name as child_name,u2.name as parent_name
from times t
join users u1
on u1.id = t.id
left
join users u2
on u2.id = u1.parent_id) allnames
join
-- poor man's pivot code:
-- 2-row dynamic table; no join clause w/ allnames will give us a
-- cartesian product; the 'case' statement will determine which
-- name (child vs parent) to display
(select 1 as pass_no
union
select 2) pass
) final
-- eliminate 'NULL' as a name in our final result set
where final.name is not NULL
order by 1
结果集:
name
==============
Alan
Bill
John