Создание групп строк с использованием ограничений подгрупп - PullRequest
0 голосов
/ 01 июля 2018

У меня есть представление в базе данных sqlite, например:

Original view

SQL Fiddle (http://www.sqlfiddle.com/#!5/ae95b/1)

Это представляет собой список ящиков и предметов, которые входят в каждый ящик. Элементы всегда заказываются по box_start, а диапазоны box_start и box_end никогда не пересекаются.

Как показано в первом ряду, есть поле, в котором можно хранить предметы с кодами от 1 включительно до 3 включительно. Например, элементы, которые будут помещены в поле A, будут «a» и «b».
Группировка элементов бокса обозначается цветом, строки с одинаковым цветом означают, что это группа.
Существуют также элементы без обозначенного поля (метка блока имеет значение null), такие как элементы «c», «f», «g», «h».

Мне нужно написать запрос, если это вообще возможно, создать специальные поля для элементов без блока и сгруппировать смежные элементы в один блок следующим образом:

Desired result

Как видно на изображении, элемент «c» и соответствующая ему ячейка были помечены как «4-4», а ранее неназначенные элементы «f», «g», «h» теперь сгруппированы под той же рамкой, помеченной « 8-10 ', что соответствует' мин (box_start от f, g, h) -макс (box_end от f, g, h) '

Я не уверен, как это сделать в SQLite. Я думал об использовании некоторого вида рекурсивного запроса с CTE, но понятия не имел, как это сделать.

1 Ответ

0 голосов
/ 01 июля 2018

После некоторой работы у меня следующий запрос:

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 Fiddle: http://www.sqlfiddle.com/#!7/4a643e/142

Несмотря на то, что он, кажется, выполняет свою работу, я не уверен, что это правильно во всех случаях, и не будет ли это узким местом в производительности.

Надеюсь, у кого-то есть лучшее решение

...