Выполнение сложных запросов на стороне сервера
Нужно было сделать отчет, который кроме выборки из таблицы включает итоговые записи (итоговая запись - это как бы сумма всех записей). Сделал с помощью вьюшки что то вроде:
[highlight=sql]
CREATE VIEW my_view (
date_field,
str_field,
int_field
)
AS
SELECT CAST(NULL AS DATE), 'ИТОГО:', SUM(int_field) FROM my_table
UNION
SELECT date_field, 'ИТОГО:', SUM(int_field) FROM my_table
GROUP BY date
UNION
SELECT * FROM my_table
;
[/highlight]
В результате в наборе данных будет вся таблица плюс итоги за каждый день плюс общий итог. Все бы хорошо, да вьюшка не позволяет передавать ей параметры. Дело в том, что мне надо делать выборку например в зависимости от периода. Если я делаю
[highlight=sql]
SELECT * FROM my_view WHERE date_field = :DATE
[/highlight]
то получается, что общий итог будет неверным, ведь он считается не по выбранным записям, а по всей таблице.
Писать большой запрос на стороне клиента (там около 50 строк, потому что здесь итоги я показал в очень упрощенном виде) мне не хочется. Если на стороне сервера, то вьюшки не подходят по вышеприведенным причинам, посмотрел на хп - они возвращают только одну запись, а не набор данных.
В общем попытаюсь сформулировать задачу:
Нужно создать на сервере что-то вроде вьюшки, но которая принимает параметры и динамически делает запрос с их применением, затем возвращает итоговый набор данных. Как можно решить такую задачу?
И да, если что БД - Firebird.
В том что вьюха содержит три разнородных группы записей, получаемых:
1-я группа записей (содержит одну запись) - получена суммированием по всей таблице;
2-я группа записей - получена группировкой по датам
3-я группа - просто записи взятые из таблицы
[highlight=sql]
SELECT * FROM my_view WHERE date_field = :DATE
[/highlight]
то получается, что общий итог будет неверным, ведь он считается не по выбранным записям, а по всей таблице.
И проблема в том, что в одном случае - нужно при выборке брать записи только из одной группы, в другом - из другой и т.д.?
Если я правильно понял суть проблемы, то в Oracle в данном случае можно было бы в каждом из образующих въюху подзапросов добавить фиктивный столбец - индикатор того, каким из подзапросов получена данная запись вьюхи, и при запросе из въюхи использовать условие по этому столбцу.
Как-то так:
[highlight="SQL"]create view my_view
AS
SELECT NULL AS date_field, 'ИТОГО:' AS str_field,
SUM(int_field) AS int_field, 1 AS period FROM my_table
UNION
SELECT date_field, 'ИТОГО:' AS str_field,
SUM(int_field) AS int_field, 2 AS period FROM my_table
GROUP BY date_field
UNION
SELECT /*список полей*/, 3 AS period FROM my_table[/highlight]
И потом в запросе из вьюхи еще накладывать условие на столбец period.
Может и в Firebird можно как-то аналогично...
представь себе, что содержится во вьюхе. всякие строки + сумма строк (буду так называть ее) всей таблицы. теперь мне надо сделать выборку за определенный период. делаю из вьюхи. получаю всякие строки + сумма строк всей таблицы. а надо всякие строки + сумма строк за период. но во вьюху никак ведь не передашь даты как параметры.
Если на стороне сервера, то вьюшки не подходят по вышеприведенным причинам, посмотрел на хп - они возвращают только одну запись, а не набор данных.
процедура может возвращать и набор данных - в чем проблема то?
[highlight=sql]
CREATE PROCEDURE my_proc
RETURNS (
date DATE,
int INTEGER,
str VARCHAR(200)
)
AS
BEGIN
SELECT CAST(NULL AS DATE), 'ИТОГО:', SUM(int_field) FROM my_table
UNION
SELECT date_field, 'ИТОГО:', SUM(int_field) FROM my_table
GROUP BY date
UNION
SELECT * FROM my_table
INTO :date, :int, :str;
SUSPEND;
END;
[/highlight]
При попытке селекта из процедуры:
[highlight=sql]SELECT * FROM my_proc
[/highlight]
получаю ошибку:
[quote=firebird]
Multiple rows in singleton select.
Multiple rows in singleton select.
At procedure 'my_proc' line: 8, col: 3.[/quote]
SELECT CAST(NULL AS DATE), 'ИТОГО:', SUM(int_field) FROM my_table
UNION
SELECT date_field, 'ИТОГО:', SUM(int_field) FROM my_table
GROUP BY date
UNION
SELECT * FROM my_table
INTO :date, :int, :str DO;
и не используй * в выборке - указывай конкретные поля. Кстати советую разделять пользовательское представление и данные.
[highlight=sql]
CREATE PROCEDURE my_proc
RETURNS (
date DATE,
int INTEGER,
str VARCHAR(200)
)
AS
BEGIN
FOR
SELECT CAST(NULL AS DATE), 'ИТОГО:', SUM(int_field) FROM my_table
UNION
SELECT date_field, 'ИТОГО:', SUM(int_field) FROM my_table
GROUP BY date
UNION
SELECT * FROM my_table
INTO :date, :int, :str
DO
SUSPEND;
END; [/highlight]
Спасибо за совет =)
ага. это я просто в примере так сделал, а вообще да, указываю.
Ну и в продолжение темы:
так я вроде стараюсь. что именно ты имеешь ввиду в данном случае?