通过使用子组限制创建行组

时间:2018-06-30 23:41:46

标签: sqlite common-table-expression

我在这样的sqlite数据库中有一个视图:

Original view

SQL小提琴 (http://www.sqlfiddle.com/#!5/ae95b/1

这表示盒子和进入每个盒子的物品的列表。项始终按box_start进行排序,范围box_startbox_end永远不会重叠。

如第一行所示,有一个盒子可以存储代码从1(含1)到3(含3)的项目。例如,将在框A中显示的项目为“ a”和“ b”。
框项分组用颜色表示,具有相同颜色的行表示它们是一个组。
也有没有指定框(框标签为空)的项目,例如“ c”,“ f”,“ g”,“ h”。

如果可能的话,我需要编写一个查询来为没有盒子的物品创建临时盒子,并将连续的物品分组到同一盒子中,如下所示:

Desired result

如图所示,项目“ c”及其对应的框标记为“ 4-4”,以前未分配的项目“ f”,“ g”,“ h”现在被分组在标记为“

对应于'f,g,h的min(box_start-f(g,h)的max(box_end)'

我不确定如何在SQLite中执行此操作。我曾考虑过对CTE使用某种递归查询,但不知道如何做。

1 个答案:

答案 0 :(得分:0)

工作后,我有以下查询:

select
    min(box_start) as box_start,
    box_end,
    box_label,
    is_box,
    item_code,
    item
from
    (
        select
            box_start,
            box_end,
            box_label,
            is_box,
            item_code,
            item
        from
            table1
        where
            box_label is not null

        union all

        select
            table1.box_start as box_start,
            table1.box_end as box_end,
            intervals.A || '-' || intervals.B as box_label,
            table1.is_box as is_box,
            table1.item_code as item_code,
            table1.item as item
        from
            (
                select
                    box_start,
                    box_end,
                    box_label,
                    is_box,
                    A,
                    B,
                    max(max_interval_size) as max_interval_size
                from
                    (
                        select
                            box_start,
                            box_end,
                            box_label,
                            is_box,
                            A,
                            B,
                            max(interval_size) as max_interval_size
                        from
                            (
                                select
                                  fixed_table.box_start as box_start,
                                  fixed_table.box_end as box_end,
                                  fixed_table.box_label as box_label,
                                  fixed_table.is_box as is_box,
                                  fixed_table.box_start as A,
                                  windowed_table.box_end as B,
                                  (windowed_table.box_end - fixed_table.box_start) as interval_size
                                from
                                  table1 fixed_table
                                  join table1 windowed_table on
                                    fixed_table.box_start <= windowed_table.box_end
                                where 
                                  interval_size >= 0
                                  and fixed_table.box_label is null
                                  and windowed_table.box_label is null
                                  and fixed_table.is_box = 'FALSE'
                                  and windowed_table.is_box = 'FALSE'

                                except

                                select
                                  without_a_box.*
                                from
                                    (
                                        select
                                          fixed_table.box_start as box_start,
                                          fixed_table.box_end as box_end,
                                          fixed_table.box_label as box_label,
                                          fixed_table.is_box as is_box,
                                          fixed_table.box_start as A,
                                          windowed_table.box_end as B,
                                          (windowed_table.box_end - fixed_table.box_start) as interval_size
                                        from
                                          table1 fixed_table
                                          join table1 windowed_table on
                                            fixed_table.box_start <= windowed_table.box_end
                                        where 
                                          interval_size >= 0
                                          and fixed_table.box_label is null
                                          and windowed_table.box_label is null
                                          and fixed_table.is_box = 'FALSE'
                                          and windowed_table.is_box = 'FALSE'
                                    ) as without_a_box
                                    ,
                                    (
                                        select distinct
                                            with_box.box_start as start_with_box
                                         from
                                            table1 with_box
                                         where
                                            with_box.is_box = 'FALSE'
                                            and with_box.box_label is not null
                                    ) as items_inside_a_box
                                where
                                    items_inside_a_box.start_with_box > without_a_box.A
                                    and items_inside_a_box.start_with_box < without_a_box.B
                            ) as without_intervals_that_intersect_boxed_items
                        group by
                            A
                    ) as final
                group by
                    B
            ) as intervals
            join table1 on
                table1.box_start >= intervals.A
                and table1.box_end <= intervals.B
                and table1.box_label is null
    )
group by
    box_label,
    is_box,
    item_code,
    item
order by
    box_start,
    item_code

SQL小提琴:http://www.sqlfiddle.com/#!7/4a643e/142

即使它似乎可以完成工作,但我不确定在所有情况下是否正确,以及它是否不会成为性能瓶颈。

我希望有人有更好的解决方案