У меня есть две таблицы, таблица счетов и таблица рабочих дней. Счета имеют много рабочих дней.
Схема рабочего дня имеет:
invoice_id: целое число, дата: дата
И скажем, схема счетов сейчас имеет только идентификатор в таблице.
С точки зрения моего приложения я хотел бы распечатать все счета, предварительно загруженные со всеми рабочими днями. Для каждого счета дочерние рабочие дни должны быть отсортированы по дате. И хотя в счете нет поля даты, мне интересно, можно ли сортировать счета по самой ранней дате среди всех соответствующих дочерних рабочих дней?
Цель состоит в том, чтобы создать представление, которое будет выглядеть примерно так:
Invoice date range: Jan 02, 2019 - Jan 03, 2019
Workdays:
Jan 02, 2019
Jan 03, 2019
Invoice date range: Jan 05, 2019 - Jan 06, 2019
Workdays:
Jan 05, 2019
Jan 06, 2019
Я использую такой запрос: выберите * из рабочих дней внутреннего соединения счета-фактуры в рабочие дни.invoice_id = счет-фактура.id порядок рабочих дней.
Но могут быть счета-фактуры не по порядку, потому что порядок в счетах-фактурах не указан. Я не знаю другого способа указать порядок сортировки в счете-фактуре без кэширования самого раннего workday.date в родительском (счет-фактуре) в новом столбце, а затем сортировки по этому дополнительному столбцу.
Обновление: я использую postgres и mysql. Под «представлением» я не подразумеваю представление базы данных (материализованное), я имел в виду модель, представление, контроллер, уровень представления.
Какой продукт СУБД вы используете? «SQL» — это просто язык запросов, а не название конкретного продукта базы данных. Добавьте ярлык для продукта базы данных, который вы используете postgresql, oracle, sql-server, db2, ...
Желаемый результат невозможен с представлением, так как каждая строка содержит разное количество столбцов. В реляционной базе данных таблица, представление или результат оператора SELECT всегда имеют одинаковое количество столбцов в каждой строке. И тип данных этого столбца фиксирован для всех строк.






Что-то типа:
select
i.id, i.comment,
min(wd.date) as invoice_range_from, max(wd.date) as invoice_range_to
from invoice i
left join workdays wd on i.id = wd.invoice_id
group by i.id
order by min(wd.date), max(wd.date)
Если вы хотите получить своих родителей-потомков за один обход сервера, используйте возможности JSON или XML вашей СУБД, особенно если ваше клиентское приложение все равно будет использовать JSON, вы можете использовать следующее. например.,
Живой тест: https://dbfiddle.uk/?rdbms=postgres_11&fiddle=0b1ce002c4380a3542387209c3c43fae
select
i.id, i.comment,
min(wd.date) as invoice_from, max(wd.date) as invoice_to,
json_agg(json_build_object('date', wd.date)) as workdays_data
from invoice i
left join workdays wd on i.id = wd.invoice_id
group by i.id
order by min(wd.date), max(wd.date)
Выход:
id comment invoice_from invoice_to workdays_data
1 Hello 2019-01-02 2019-01-03 [{"date" : "2019-01-02"}, {"date" : "2019-01-03"}]
2 Hola 2019-01-05 2019-01-06 [{"date" : "2019-01-05"}, {"date" : "2019-01-06"}]
В противном случае вам придется использовать возможности пакетной обработки вашего ORM. Если у вас нет подходящего ORM, вам нужно вручную сделать запрос минимальным для сервера.
Если вы хотите полностью использовать возможности JSON вашей СУБД для рендеринга древовидных данных за один раз, вы можете:)
Живой тест: https://dbfiddle.uk/?rdbms=postgres_11&fiddle=1ed3105719ed033ba568e01b3d97c234
with a as
(
select
i.id, i.comment,
min(wd.date) as invoice_range_from, max(wd.date) as invoice_range_to,
json_agg(json_build_object('date', wd.date)) as workdays_data
from invoice i
left join workdays wd on i.id = wd.invoice_id
group by i.id
order by min(wd.date), max(wd.date)
)
select json_agg(a.*) from a;
Выход:
[
{
"id": 1,
"comment": "Hello",
"invoice_range_from": "2019-01-02",
"invoice_range_to": "2019-01-03",
"workdays_data": [
{
"date": "2019-01-02"
},
{
"date": "2019-01-03"
}
]
},
{
"id": 2,
"comment": "Hola",
"invoice_range_from": "2019-01-05",
"invoice_range_to": "2019-01-06",
"workdays_data": [
{
"date": "2019-01-05"
},
{
"date": "2019-01-06"
}
]
}
]
Схема:
create table invoice
(
id int primary key,
comment text not null
);
create table workdays
(
invoice_id int not null references invoice(id),
id int not null generated by default as identity primary key,
date date not null
);
insert into invoice(id, comment) values
(1, 'Hello'),
(2, 'Hola');
insert into workdays(invoice_id, date) values
(1, '2019-1-2'),
(1, '2019-1-3'),
(2, '2019-1-5'),
(2, '2019-1-6');
Вы должны использовать подзапрос
existsсWith, если вы повторно используете таблицу, для поискаmax()даты, а такжеleftдля таких вещей, как «даже если в счете нет поля даты». Без данных, примеров и прочего сложно ответить.