Firebird хранимая процедура для объединения всех значений полей из нескольких строк
-
06-07-2019 - |
Вопрос
Моя цель - написать сохраненный процесс, который может собирать все значения полей из нескольких строк в одну выходную переменную (возможно, varchar (some_length)). Это может показаться странным решением, но я вполне уверен, что это единственное, что я могу использовать в той ситуации, в которой я нахожусь. Я раньше не использовал Firebird, и хранимые процессы выглядят иначе, чем в других известных системах БД. Мой Firebird 1,5 и диалект 3 (не уверен, что это значит). Так что, может быть, кто-то может помочь мне с примером алгоритма.
Решение
Следующая процедура делает то, что вы описываете:
SET TERM !!;
CREATE PROCEDURE concat_names
RETURNS (concat VARCHAR(2000))
AS
DECLARE VARIABLE name VARCHAR(100);
BEGIN
concat = '';
FOR SELECT first_name || ' ' || last_name FROM employee INTO :name
DO BEGIN
concat = concat || name || ', ';
END
END!!
SET TERM ;!!
EXECUTE PROCEDURE concat_names;
Но я подвергаю сомнению мудрость этого решения. Откуда вы знаете, что VARCHAR достаточно длинный для всех строк в нужном вам наборе данных?
Гораздо проще и безопаснее выполнить запрос, чтобы возвращать результат в приложение строка за строкой. У каждого языка программирования приложений есть методы для объединения строк, но что более важно, у них есть более гибкие методы для управления ростом данных.
Кстати, "диалект" в Firebird и InterBase относится к режиму совместимости, который был введен для того, чтобы приложения, разработанные для InterBase 5.x, могли работать с более поздними версиями InterBase и Firebird. Это было почти десять лет назад, и AFAIK сегодня нет необходимости использовать что-либо ниже, чем диалект 3.
Другие советы
При конкатенации вы должны проверить нулевые значения, вот пример для двух полей и разделителя между ними:
CREATE PROCEDURE CONCAT(
F1 VARCHAR(385),
F2 VARCHAR(385),
SEPARATOR VARCHAR(10))
RETURNS (
RESULT VARCHAR(780))
AS
begin
if ((:f1 is not null) and (:f1 <> '')) then
result = :f1;
if ((:f2 is not null) and (:f2 <> '')) then
if ((result is not null) and (result <> '')) then
begin
if ((:separator is not null) and (separator <> '')) then
result = result||separator||f2;
else
result = result||f2;
end
else
result = f2;
suspend;
end
Возврат нескольких строк с использованием хранимых процедур Firebird очень прост.
Не используйте:
execute procedure proc_name(value);
Вместо этого используйте:
select * from proc_name(value);