SQL, Firebird, Dynamic Union на основе другой таблицы

Мне нужна ваша помощь. Мне нужно построить оператор динамического объединения SQL. (Или хранимая процедура)

В TableA1 хранятся значения моих параметров SQL. Например:

ID | Name
1 | 16
2 | 23
3 | 30

В TableB1 хранятся все остальные значения. Но мне нужно для каждой строки в таблице A1 объединение

Например:

Select b.* from TableB1 b
join TableA1 a on a.ID = b.ID
where b.ID = 1
union
Select b.* from TableB1
join TableA1 a on a.ID = b.ID
where b.ID = 2

Поскольку таблица A1 является динамической, невозможно создать статический union-sql. Помогите мне, пожалуйста. Могу ли я сделать это, возможно, с помощью: cte WITH ?

С уважением рф

Второе объяснение: я постараюсь сделать свое объяснение более понятным. Извините за мой первый вопрос. Я вижу, это было не правильно.

Мне нужно динамическое объединение (или что-то еще) из-за дизайна таблицы TableB1. Значения хранятся каждый месяц/год в горизонтальном порядке.

Пример TableB1:

date    | xxxx | ID1 |  ID2 | ID3 | ID4 ...
2014-07 | n    |  20 |   30 |  40 |
2014-08 | n    |  40 |   50 |  70 |

Вывод должен выглядеть так:

TableB1.date | TableA1.ID | TableA1.Name | TableB1.ID x |
2014-07      |          1 |         16   |    20    
2014-08      |          1 |         16   |    40
2014-07      |          2 |         23   |    30      
2014-08      |          2 |         23   |    50
2014-07      |          3 |         30   |    40      
2014-08      |          3 |         30   |    70

Я думал, что помещу sql в хранимую процедуру, потому что для каждого объединения мне нужно изменить синтаксис SQL, чтобы получить правильный столбец.

Возможно, мне нужно сначала создать хранимую процедуру unpivot. У вас есть идеи, как я могу сделать это в Firebird?


person birtprofi    schedule 18.08.2014    source источник
comment
Можете ли вы предоставить пример ожидаемого результата? Почему вы не можете просто сделать: Select b.* from TableB1 b join TableA1 a on a.ID = b.ID?   -  person StevieG    schedule 18.08.2014
comment
Читая ваш запрос и вашу проблему, я вижу, что вы выбираете содержимое TableB1 для объединения и ничего не делаете с TableA1. Также обратите внимание: почему бы не избежать объединения и не использовать предикат IN ?   -  person Jaaz Cole    schedule 18.08.2014
comment
Это Firebird или SQL-сервер? Почему оба тега?   -  person Frazz    schedule 18.08.2014
comment
@Frazz: потому что программное обеспечение может использовать установку Firebird или базу данных MSSQL. Обе базы данных поддерживаются   -  person birtprofi    schedule 19.08.2014
comment
Структура TableB1, очевидно, является проблемой. Вы хотите использовать идентификатор TableA1 для выбора столбца из TableB1. Не можете ли вы изменить структуру TableB1, чтобы иметь одну строку для каждой даты и идентификатора, а также один столбец значений? Это было бы лучшим решением для запросов и обслуживания. В противном случае вам понадобятся сложные операторы CASE или STORED PROCEDURE. Но ни один из них не будет достаточно гибким, чтобы адаптироваться, когда вы добавите новые идентификаторы в таблицу A1 (и новые столбцы в таблицу B1).   -  person Frazz    schedule 19.08.2014


Ответы (1)


Я не уверен, что представляет собой поле xxxx в таблице B1, но я предполагаю, что у вас нет поля идентификатора в таблице B1, и для каждого идентификатора в таблице A1 вам нужно соответствующее поле IDx из таблицы B1. Я также предполагаю, что ваши поля идентификатора являются числовыми, а имя - числовым. Вот пример кода внутри EXECUTE BLOCK, но его легко поместить в STORED PROCEDURE. Причина для блока выполнения заключается в том, что он делает его гибким, например, при выполнении через ADO.

Я развил идею, которую Фразз сказал реструктурировать TableB1.

Вам понадобится следующая временная таблица

CREATE GLOBAL TEMPORARY TABLE GTT_TEMP (
    DT   VARCHAR(10),
    ID   INTEGER,
    VAL  INTEGER
) ON COMMIT DELETE ROWS;

а вот SQL

EXECUTE BLOCK
returns (TableB1_DATE VARCHAR(10),
         TableA1_ID INTEGER,
         tableA1_Name INTEGER,
         tableB1_ID INTEGER )
as
declare variable sql varchar(1000);
declare variable id integer;
begin

    for
    Select TABLEA1.ID FROM TABLEA1
    INTO :id
    do
    begin
       sql = 'INSERT INTO GTT_TEMP ( DT, ID, VAL ) SELECT tableb1."DATE", '||:id||', ID'||:id||' from tableb1 WHERE tableb1.ID'||:id||' > 0' ;
       EXECUTE Statement :sql;
    end

    FOR 
    Select GTT_TEMP.DT, GTT_TEMP.ID, tablea1.NAME, GTT_TEMP.VAL from GTT_TEMP, TABLEA1 WHERE tablea1.ID = gtt_temp.ID
    INTO :TableB1_DATE,
         :TableA1_ID,
         :TableA1_NAME,
         :TableB1_ID
     DO
     BEGIN
        suspend;
     END

END
person Ed Mendez    schedule 20.08.2014