Отобразить два несвязанных запроса на выборку без взаимных полей в одной процедуре Firebird

Как правильно отобразить два несвязанных запроса на выборку без взаимных полей в процедуре?

Table1
        Number
          1
          2
          3
          4
          5

Table2
        Letter
          a

Когда я пытаюсь вызвать их, используя эту процедуру,

CREATE PROCEDURE SAMPLE
RETURNS(
  Number SMALLINT,
  Letter Varchar)
AS
BEGIN
  FOR
    SELECT
      A.Number,
      B.Letter
    FROM Table1 A, Table2 B
    INTO
      :Number,
      :Letter
  DO
    BEGIN
      SUSPEND;
    END
END;

я получаю этот результат

Number Letter
  1      a
  2      a
  3      a
  4      a
  5      a

вот мой желаемый результат

   Number Letter
      1      a
      2      
      3      
      4      
      5      

1 ответ

Предполагая, что вы хотите, чтобы результирующий набор несвязанных наборов был "заархивирован", вы должны назначить каждой строке из любой таблицы номер строки (используя Firebird 3 row_number()) и затем присоединиться к нему (используя внешнее соединение, поэтому не имеет значения, у кого больше строк).

Это приведет к запросу, который выглядит следующим образом:

select a.number, b.letter
from (select row_number() over() as t1nr, number from table1) a
full outer join (select row_number() over() as t2nr, letter from table2) b
    on a.t1nr = b.t2nr

Обратите внимание, что в зависимости от ваших потребностей, вы можете указать явный порядок для row_number(), например row_number() over(order by number) а также row_number() over(order by letter),

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

Вы можете сделать что-то, как я покажу ниже (я использую Firebird 3, но замена этих логических значений на smallint и использование 1 и 0 должна работать с Firebird 2.0 - 2.5). Для удобства чтения я использовал имена таблиц numbers а также letters вместо table1 а также table2

execute block returns (number integer, letter char(1))
as
  declare cur_numbers cursor for (select number from numbers);
  declare cur_letters cursor for (select letter from letters);
  declare all_numbers_fetched boolean = false;
  declare all_letters_fetched boolean = false;
begin
  open cur_numbers;
  open cur_letters;
  while (true) do
  begin

    if (not all_numbers_fetched) then
    begin
      -- fetch a single row from numbers
      fetch cur_numbers into :number;
      if (row_count = 0) then
      begin
        -- all numbers fetched
        close cur_numbers;
        all_numbers_fetched = true;
        number = null;
      end
    end

    if (not all_letters_fetched) then
    begin
      -- fetch a single row from letters
      fetch cur_letters into :letter;
      if (row_count = 0) then
      begin
        -- all letters fetched
        close cur_letters;
        all_letters_fetched = true;
        letter = null;
      end
    end

    if (all_numbers_fetched and all_letters_fetched) then
      leave;

    suspend;
  end
end
Другие вопросы по тегам