由父母分页时,应向子女展示

时间:2019-08-02 17:23:49

标签: sql oracle pagination hierarchical-data window-functions

我有一个包含父行和子行的结果集。 (子行永远不会有子级)。 我需要对其进行分页(考虑排序),以便:

首先需要仅在分页页面上选择父级(例如,当页面大小= 10时,它必须包含<= 10个父级行),然后 在分页页面上将那些父母的孩子“粘”在他们身上。

源结果集如下:

+----+-----------+-------------+
| ID | PARENT_ID | SORT_COLUMN |
+----+-----------+-------------+
|  1 |           | y           |
|  2 |         1 | z           |
|  3 |           | u           |
|  4 |           | q           |
|  5 |         4 | o           |
|  6 |         4 | p           |
|  7 |           | c           |
+----+-----------+-------------+

所需的结果:

+----+-----------+-------------+----+----------+
| ID | PARENT_ID | SORT_COLUMN | RN | RN_CHILD |
+----+-----------+-------------+----+----------+
|  7 |           | c           |  1 |          |
|  4 |           | q           |  2 |          |
|  5 |         4 | o           |  2 |        1 |
|  6 |         4 | p           |  2 |        2 |
|  3 |           | u           |  3 |          |
|  1 |           | y           |  4 |          |
|  2 |         1 | z           |  4 |        1 |
+----+-----------+-------------+----+----------+

现在我这样做:

with
  cte as
    (select 1 as id, null as parent_id, 'y' as sort_column from dual
     union all
     select 2 as id, 1 as parent_id, 'z' as sort_column from dual
     union all
     select 3 as id, null as parent_id, 'u' as sort_column from dual
     union all
     select 4 as id, null as parent_id, 'q' as sort_column from dual
     union all
     select 5 as id, 4 as parent_id, 'o' as sort_column from dual
     union all
     select 6 as id, 4 as parent_id, 'p' as sort_column from dual
     union all
     select 7 as id, null as parent_id, 'c' as sort_column from dual)
select 
  *
from
  (select
    t.*, 
    dense_rank() over (order by 
                         case when t.parent_id is null 
                           then 
                             t.sort_column 
                           else 
                             (select t2.sort_column from cte t2 where t2.id = t.parent_id) 
                         end) as RN,
    case 
      when parent_id is null 
        then
          null 
        else 
          row_number() over (partition by t.parent_id order by t.sort_column) 
    end as RN_CHILD
from cte t)
--where RN between :x and :y
order by RN, RN_CHILD nulls first

但是我认为可以做到这一点而无需对结果集进行不必要的额外访问。 (select t2.sort_column from cte t2 where t2.id = t.parent_id

如何做到?

UPD::父母必须按sort_column排序,父母中的孩子也必须按sort_column排序。

3 个答案:

答案 0 :(得分:0)

首先,values语句有一个窍门,其次,您可以使用左连接并合并以获取所需的内容,例如:

FROM python:3.7.1-alpine

RUN mkdir -p /opt/project/todo_api
RUN pip --no-cache-dir install poetry

COPY ./pyproject.toml /opt/project
COPY poetry.lock /opt/project

RUN cd /opt/project && poetry install --no-dev

COPY ./todo_api /opt/project/todo_api
COPY ./todo_api.yml /opt/project/todo_api.yml

WORKDIR /opt/project

ENTRYPOINT poetry run python -m aiohttp.web todo_api.main:main

答案 1 :(得分:0)

对于RN,您需要使用DENSE_RANK,对于CHILD_RN,您需要使用ROW_NUMBER

with
  cte(id,parent_id,sort_column) as
    ( 
        SELECT 1, null, 'y' FROM DUAL UNION ALL
        SELECT 2, 1   , 'z' FROM DUAL UNION ALL
        SELECT 3, null, 'u' FROM DUAL UNION ALL
        SELECT 4, null, 'q' FROM DUAL UNION ALL
        SELECT 5, 4   , 'o' FROM DUAL UNION ALL
        SELECT 6, 4   , 'p' FROM DUAL UNION ALL
        SELECT 7, null, 'c' FROM DUAL
    )
SELECT
    C.*,
    DENSE_RANK() OVER(
        ORDER BY
            (CASE
                WHEN C.PARENT_ID IS NOT NULL THEN C.PARENT_ID
                ELSE C.ID
            END) DESC NULLS FIRST
    ) AS RN,
    CASE
        WHEN C.PARENT_ID IS NOT NULL THEN ROW_NUMBER() OVER(
            PARTITION BY C.PARENT_ID
            ORDER BY
                C.ID
        )
    END AS CHILD_RN
FROM
    CTE C
ORDER BY
    RN;

输出:

        ID  PARENT_ID S         RN   CHILD_RN
---------- ---------- - ---------- ----------
         7            c          1           
         4            q          2           
         5          4 o          2          1
         6          4 p          2          2
         3            u          3           
         2          1 z          4          1
         1            y          4           

7 rows selected. 

干杯!

答案 2 :(得分:0)

就我而言,可以使用connect_by_root子句来代替对结果集的额外访问:

(此外,我注意到我的原始SQL包含一个错误-值相同的sort_column的父母有相同的RN的价值,此问题已在此处修复)

with
  cte(id, parent_id, sort_column) as
    (select 1, null, 'y' from dual union all
     select 2, 1,    'z' from dual union all
     select 3, null, 'u' from dual union all
     select 4, null, 'q' from dual union all
     select 5, 4,    'o' from dual union all
     select 6, 4,    'p' from dual union all
     select 7, null, 'c' from dual)
select 
  *
from
  (select
    t.*, 
    case when t.parent_id is null
      then
        row_number() over (partition by parent_id order by t.sort_column)
      else
        dense_rank() over (order by connect_by_root sort_column)
    end as RN as RN,
    case 
      when parent_id is null 
        then
          null 
        else 
          row_number() over (partition by t.parent_id order by t.sort_column) 
    end as RN_CHILD
from cte t
connect by prior id = parent_id
start with parent_id is null)
--where RN between :x and :y
order by RN, RN_CHILD nulls first