Sqlite限制具有相同ID的重复行

时间:2021-07-12 06:53:45

标签: android database sqlite android-sqlite common-table-expression

我正在使用 android SQLite 数据库,结果如下:

 id | root_id | parent_id   |name
----------------------------------
613 | null    | null        | m1
612 | null    | null        | m4
570 | null    | null        | m1
635 | 570     | 570         | m6
653 | 570     | 635         | m1
652 | 570     | 635         | m3
632 | 570     | 570         | m9
392 | null    | null        | m2
753 | 392     | 392         | m5
751 | 392     | 392         | m4
391 | null    | null        | m7

我通过下面的查询得到了这个结果:

WITH RECURSIVE all_employees(id, root_id, parent_id, name) AS (
    SELECT id, id AS root_id, parent_id, name FROM employees WHERE parent_id IS NULL
    UNION ALL
    SELECT c.id, (CASE WHEN c.parent_id IS NOT NULL THEN p.root_id END), c.parent_id, c.name FROM employees c JOIN all_employees p ON p.id = c.parent_id ORDER BY id DESC
)

SELECT id, (CASE WHEN id != root_id THEN root_id ELSE NULL END) root_id, parent_id, name FROM all_employees

我想为具有相同root_id的重复行设置限制,例如: 加载 2 行 root_id 570 和 1 行 root_id 392:

 id | root_id | parent_id   |name
----------------------------------
613 | null    | null        | m1
612 | null    | null        | m4
570 | null    | null        | m1
635 | 570     | 570         | m6
653 | 570     | 635         | m1
392 | null    | null        | m2
753 | 392     | 392         | m5
391 | null    | null        | m7

3 个答案:

答案 0 :(得分:1)

有限选择的联合

WITH RECURSIVE all_employees(id, root_id, parent_id, name) AS (
    SELECT id, id AS root_id, parent_id, name 
    FROM employees 
    WHERE parent_id IS NULL
    UNION ALL
    SELECT c.id, (CASE WHEN c.parent_id IS NOT NULL THEN p.root_id END), c.parent_id, c.name 
    FROM employees c 
    JOIN all_employees p ON p.id = c.parent_id ORDER BY id DESC
)
SELECT id, root_id, parent_id, name
FROM all_employees
where root_id not in (570, 392)
union all
select *
from (
   select *
   from all_employees
   where root_id =570 
   limit 3
)
union all
select *
from (
   select *
   from all_employees
   where root_id =392
   limit 2
)

答案 1 :(得分:1)

创建另一个CTE

counters(root_id, n) AS (VALUES (570, 2), (392, 1)) 

返回所有要限制其行的所有 root_id 以及每个行的行数,然后使用递归 LEFTCTE 连接。
最后,使用相关子查询在 WHERE 子句中设置条件:

WITH 
  RECURSIVE all_employees(id, root_id, parent_id, name) AS (
    SELECT id, id AS root_id, parent_id, name 
    FROM employees 
    WHERE parent_id IS NULL
    UNION ALL
    SELECT c.id, (CASE WHEN c.parent_id IS NOT NULL THEN p.root_id END), c.parent_id, c.name 
    FROM employees c JOIN all_employees p 
    ON p.id = c.parent_id 
  ),
  counters(root_id, n) AS (VALUES (570, 2), (392, 1))
SELECT a.id, (CASE WHEN a.id <> a.root_id THEN a.root_id END) root_id, a.parent_id, a.name
FROM all_employees a LEFT JOIN counters c
ON c.root_id = a.root_id
WHERE c.root_id IS NULL 
   OR (SELECT COUNT(*) FROM all_employees b WHERE b.root_id IS a.root_id AND b.id <= a.id) <= c.n

请注意,ORDER BY 中的 CTE 子句是无用的,因为当您从 CTE 中选择时,不能保证行会按该顺序返回。
您可以在最终查询中设置所需行的顺序。

答案 2 :(得分:0)

向 CTE 添加一个计数器,然后使用 WHERE 逻辑进行过滤:

WITH RECURSIVE all_employees(id, root_id, parent_id, name, lev) AS (
    SELECT id, id AS root_id, parent_id, name, 0 as lev
    FROM employees
    WHERE parent_id IS NULL
    UNION ALL
    SELECT c.id,
           (CASE WHEN c.parent_id IS NOT NULL THEN p.root_id END), c.parent_id, c.name, p.lev + 1
    FROM employees c JOIN
         all_employees p
         ON p.id = c.parent_id
    ORDER BY id DESC   -- don't think this does anything
   )
SELECT id, (CASE WHEN id <> root_id THEN root_id END) as root_id, parent_id, name
FROM all_employees
WHERE root_id = 570 AND cnt <= 1 OR
      root_id = 392 AND cnt <= 2 OR
      root_id NOT IN (570, 392);

这里的重点是将计数放入递归 CTE,然后使用该信息进行过滤。您可以随意使用 WHERE 子句:

WHERE (CASE WHEN root_id = 570 THEN cnt <= 1
            WHEN root_id = 392 THEN cnt <= 2
            ELSE 1
       END)
            
相关问题