【问题标题】:Sqlite limit repeated rows with same idSqlite 限制具有相同 id 的重复行
【发布时间】:2021-09-21 08:46:54
【问题描述】:

我正在使用 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

【问题讨论】:

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


    【解决方案1】:

    创建另一个CTE

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

    您返回所有要限制其行的root_ids 以及每行的行数,然后使用递归CTELEFT 连接。
    最后,在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
    

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

    【讨论】:

    • 谢谢,关于我想要某种树顺序的顺序,当我在CTE 中使用ORDER BY 时,它给出了正确的顺序。
    • @ali-star 子查询或 CTE 中的 ORDER BY 子句(除非它与 LIMIT 一起使用)不能保证会影响最终结果。为了安全起见,请始终在最终查询中使用 ORDER BY 子句。
    【解决方案2】:

    有限选择的联合

    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
    )
    

    【讨论】:

    • 谢谢,但问题是row_number()partition by在android SQLite版本中不可用。
    • 或者使用多个UNION ALL .. SELECT .. LIMIT..
    • 太好了,但我怎样才能让它充满活力?
    • 可能会根据参数或用户输入在您的应用中构建它。
    • 是的,这是我的 B 计划,因为我正在使用分页库。
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2015-11-30
      • 2016-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-02
      • 2020-01-09
      • 2018-01-28
      相关资源
      最近更新 更多