Транспонировать столбцы и строки в Firebird 2.5 - PullRequest
0 голосов
/ 06 июня 2018

Я написал процедуру в Firebird (Диалект 3), которая возвращает мне что-то вроде этого:

 column1  |  column2    |  column3  |   column4  |  ...
----------|-------------|-----------|------------|--------
 1        |  55         |  2.5      |    100€    |  ...

Конкретные имена столбцов на самом деле не имеют значения.Я получаю к нему доступ вот так

SELECT * FROM MY_PROCEDURE(:START_DATE, :END_DATE);

Он возвращает только одну строку, поэтому я думаю, что я мог бы также получить к нему доступ с помощью EXECUTE_PROCEDURE.Теперь я хочу переставить столбцы и строки в возвращаемом

 row      |  result    
----------|---------
 column1  |  1    
 column2  |  55    
 column3  |  2.0   
 column4  |  100€    
 ...      |  ...  

. Первоначально я сделал что-то вроде этого:

select 'column1' AS row, column1 AS result
FROM MY_PROCEDURE(:START_DATE, :END_DATE)
union all
select 'column2' AS row, column2 AS result
FROM MY_PROCEDURE(:START_DATE, :END_DATE)
union all
...

В основном один запрос для каждого столбца.Это сработало.Однако в конце концов я столкнулся с этой проблемой:

Dynamic SQL Error
Too many Contexts of Relation/Procedure/Views. Maxium allowed is 255.

Так что мне нужно реструктурировать свой скрипт.Как вы можете видеть, мои знания SQL довольно посредственны, и я просто не знаю, как извлечь каждый столбец как строку за один выбор.

Кто-нибудь сможет помочь?Заранее спасибо.

1 Ответ

0 голосов
/ 07 июня 2018

Firebird сам по себе без unpivot или другой встроенной поддержки для транспонирования столбцов.

«Лучшим» и, возможно, наиболее эффективным решением будет переписать MY_PROCEDURE (или написатьальтернативная версия) для вывода транспонированных строк.

Например, если ваша хранимая процедура делает что-то вроде этого:

set term #;
create procedure test_1 
    returns (id integer, column1 double precision, column2 double precision, column3 double precision)
as
begin 
    for 
        select id, column1, column2, column3 
        from sometable 
        into :id, :column1, :column2, :column3 do
    begin
        suspend;
    end
end#
set term ;#

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

set term #;
create procedure test_2 
    returns (id integer, columnname varchar(100), columnvalue double precision)
as
declare column1 double precision;
declare column2 double precision;
declare column3 double precision;
begin 
    for 
        select id, column1, column2, column3 
        from sometable 
        into :id, :column1, :column2, :column3 do
    begin
        columnname = 'column1';
        columnvalue = column1;
        suspend;
        columnname = 'column2';
        columnvalue = column2;
        suspend;
        columnname = 'column3';
        columnvalue = column3;
        suspend;
    end
end#
set term ;#

Это выведет что-то вроде

id  columnname columnvalue
1   column1    1.0
1   column2    1.5
1   column3    5.0
2   ...etc

Это решение требует, чтобы все выходные данные (columnvalue) имели одинаковый тип.В противном случае вам нужно привести к общему типу данных.

В качестве альтернативы вы можете связать первую процедуру со второй процедурой, используя for select * from test_1 into ....Это может быть более или менее эффективным в зависимости от внутренней части вашей хранимой процедуры:

set term #;
create procedure test_3 
        returns (id integer, columnname varchar(100), columnvalue double precision)
as
declare column1 double precision;
declare column2 double precision;
declare column3 double precision;
begin 
    for 
        select id, column1, column2, column3 from test_1
        into :id, :column1, :column2, :column3 do
    begin
        columnname = 'column1';
        columnvalue = column1;
        suspend;
        columnname = 'column2';
        columnvalue = column2;
        suspend;
        columnname = 'column3';
        columnvalue = column3;
        suspend;
    end
end#
set term ;#

Этот последний вариант, вероятно, лучше всего подходит, если вам нужны оба варианта вывода, поскольку это означает, что у вас будет только одно место длялогика этой хранимой процедуры.

Для специальных запросов вы также можете заменить хранимую процедуру на execute block тем же кодом.

...