在子数学条件下选择父记录

时间:2019-04-08 21:15:12

标签: mysql sybase pervasive faircom-db-sql

我试图将用户返回的结果限制为“最近”的结果,但是如果用户有父母,我还需要返回父母。

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

在这种情况下,我想返回Alan,John和Bill,但不返回Jerry,因为Jerry在times表中没有记录,他也不是拥有记录的人的父母。我不知道该如何处理Carl,我不介意为他获得结果,但是我不需要它们。

我正在用成千上万的{{​​1}}记录来筛选成千上万的用户,因此性能非常重要。通常,我有来自times的3000个唯一ID,可以是timesid

上面是我尝试做的一个精简示例,完整的示例包括更多的联接和case语句,但是总的来说,上面的示例应该是我们要使用的示例,但这是我查询的示例正在使用(完整查询将近100行):

parent_id

此示例适用于Faircom C-Tree数据库,但我还需要在Sybase,MySql和Pervasive中实现类似的解决方案,因此仅尝试了解为实现最佳性能而应该做的事情。

基本上,我需要做的是以某种方式使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 也包括用户父级。

1 个答案:

答案 0 :(得分:0)

注意:

  • 基于您的小提琴配置,我假设您使用的是MySQL 5.6,因此不支持通用表表达式(CTE)

  • 我假设每个名称(孩子或父母)在最终结果集中都应作为单独的记录显示

我们想限制我们必须联接timesusers表的次数(CTE可以使它更易于编码/读取)。

主查询(时间-> users(u1)-> users(u2))将在单独的列中给我们提供子名称和父名称,因此我们将使用2行动态表和一个case语句以便将各列转到各自的行中(注意:我不使用MySQL,也没有时间研究MySQL 5.6是否具有pivot功能)

-- 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

MySQL fiddle