Вложенные выражения регистра в функциях SQL с многостолбцовым вводом - PullRequest
2 голосов
/ 29 февраля 2020

Я пытаюсь понять, правильно ли я вкладываю эти выражения case. Это оптимальный способ go о вложении этих?

Чтобы объяснить, что я пытаюсь сделать здесь, создайте функцию, которая просматривает три столбца в одной таблице. Строковый результат определяется на основе найденного ввода. Если ввод не найден в столбце 1 (он же тест), то он перемещается в столбец 2 (транспонирование), а затем в столбец 3 (построение) до тех пор, пока не будет найден какой-либо результат или он не перейдет.

I ' Я не уверен, что это лучший и или правильный способ go об этой ситуации. Любые предложения будут с благодарностью.

CREATE OR REPLACE FUNCTION any_class(test TEXT, transpose TEXT, construction TEXT) RETURNS TEXT AS $$
    SELECT CASE
        WHEN test IN ('a', 'b') THEN 'result1'
        WHEN test IN ('c', 'd') THEN 'result2'
        WHEN test IN ('e', 'f') THEN 'result3'
        WHEN test IN ('g', 'h') THEN 'result4'
        WHEN test IN ('i', 'j') THEN 'result5'
        WHEN test IN ('k', 'l', 'm') THEN 'result6'
        WHEN test IN ('n') THEN 'result7'
        WHEN test IN ('o') THEN 'result8'
        WHEN test IN ('p') THEN 'result9'
        WHEN test IN ('q', 'r', 's', 't', 'u') THEN 'result10'
        ELSE CASE
            WHEN transpose IN ('a', 'b') THEN 'result1'
            WHEN transpose IN ('c', 'd') THEN 'result2'
            WHEN transpose IN ('e', 'f') THEN 'result3'
            WHEN transpose IN ('g', 'h') THEN 'result4'
            WHEN transpose IN ('i', 'j') THEN 'result5'
            WHEN transpose IN ('k', 'l', 'm') THEN 'result6'
            WHEN transpose IN ('n') THEN 'result7'
            WHEN transpose IN ('o') THEN 'result8'
            WHEN transpose IN ('p') THEN 'result9'
            WHEN transpose IN ('q', 'r', 's', 't', 'u') THEN 'result10'
            ELSE CASE
                WHEN construction IN ('a', 'b') THEN 'result1'
                WHEN construction IN ('c', 'd') THEN 'result2'
                WHEN construction IN ('e', 'f') THEN 'result3'
                WHEN construction IN ('g', 'h') THEN 'result4'
                WHEN construction IN ('i', 'j') THEN 'result5'
                WHEN construction IN ('k', 'l', 'm') THEN 'result6'
                WHEN construction IN ('n') THEN 'result7'
                WHEN construction IN ('o') THEN 'result8'
                WHEN construction IN ('p') THEN 'result9'
                WHEN construction IN ('q', 'r', 's', 't', 'u') THEN 'result10'
                END
            END
    END;
$$
LANGUAGE SQL
IMMUTABLE PARALLEL SAFE;

Ответы [ 3 ]

2 голосов
/ 29 февраля 2020

Логика c в вашей функции выглядит нормально, и я думаю, что она делает то, что вам нужно.

Одним из способов сократить код (и сделать его более масштабируемым) было бы использование внутренней функции который проверяет один параметр, а затем вызывает его несколько раз в пределах COALESCE() во внешней функции, например:

CREATE OR REPLACE FUNCTION any_class(test TEXT, transpose TEXT, construction TEXT) 
RETURNS TEXT 
AS $any_class$      
    DECLARE res text;
    BEGIN

    CREATE OR REPLACE FUNCTION one_class(val TEXT) 
    RETURNS text 
    AS $one_class$
        SELECT CASE
            WHEN val IN ('a', 'b') THEN 'result1'
            WHEN val IN ('c', 'd') THEN 'result2'
            WHEN val IN ('e', 'f') THEN 'result3'
            WHEN val IN ('g', 'h') THEN 'result4'
            WHEN val IN ('i', 'j') THEN 'result5'
            WHEN val IN ('k', 'l', 'm') THEN 'result6'
            WHEN val IN ('n') THEN 'result7'
            WHEN val IN ('o') THEN 'result8'
            WHEN val IN ('p') THEN 'result9'
            WHEN val IN ('q', 'r', 's', 't', 'u') THEN 'result10'
      END;
    $one_class$ language sql;

    SELECT COALESCE(one_class(test), one_class(transpose), one_class(construction)) INTO res;
    RETURN res;

    END;
$any_class$ 
language plpgsql;

Демонстрация на DB Fiddle - вы можете поиграться с аргументами функций, чтобы убедиться, что они дают результаты, идентичные существующему коду.

1 голос
/ 29 февраля 2020

Вы можете сделать это с одним большим case выражением:

(CASE WHEN test IN ('a', 'b') THEN 'result1'
      WHEN test IN ('c', 'd') THEN 'result2'
      . . .
      WHEN transpose IN ('a', 'b') THEN 'result1'
      WHEN transpose IN ('c', 'd') THEN 'result2'
      . . .
      WHEN construction IN ('a', 'b') THEN 'result1'
      WHEN construction IN ('c', 'd') THEN 'result2'
      . . .
 END)

Нет необходимости их вкладывать.

Вы, похоже, хотите расставить приоритеты в порядке просмотра колонны. В противном случае, если вы хотите расставить приоритеты по возвращаемым значениям, я бы предложил:

(CASE WHEN test IN ('a', 'b') OR transpose IN ('a', 'b') OR construction IN ('a', 'b')
      THEN 'result1'
      . . .
 END)
1 голос
/ 29 февраля 2020

Может быть, оператор перекрытия массива &&, который проверяет, имеют ли два массива хотя бы один общий элемент, может немного облегчить ситуацию. Используя его, вам не нужно вкладывать выражения CASE, но иметь только одно.

SELECT CASE
         WHEN ARRAY[test,
                    transpose,
                    construction]
              && ARRAY['a',
                       'b']) THEN
           'result1'
         WHEN ARRAY[test,
                    transpose,
                    construction]
              && ARRAY['c',
                       'd']) THEN
           'result2'
         ...
         WHEN ARRAY[test,
                    transpose,
                    construction]
              && ARRAY['q',
                       'r',
                       's',
                       't',
                       'u']) THEN
           'result10'
       END;

Другой вариант - INTERSECT отношения с помощью предложений VALUES и проверка, если пересечение пусто с EXISTS.

SELECT CASE
         WHEN EXISTS (SELECT *
                             FROM (VALUES (test),
                                          (transpose),
                                          (construction)) r1 (c1)
                      INTERSECT
                      SELECT *
                             FROM (VALUES ('a'),
                                          ('b')) r2 (c1))
           'result1'
         WHEN EXISTS (SELECT *
                             FROM (VALUES (test),
                                          (transpose),
                                          (construction)) r1 (c1)
                      INTERSECT
                      SELECT *
                             FROM (VALUES ('c'),
                                          ('d')) r2 (c1))
           'result2'
         ...
         WHEN EXISTS (SELECT *
                             FROM (VALUES (test),
                                          (transpose),
                                          (construction)) r1 (c1)
                      INTERSECT
                      SELECT *
                             FROM (VALUES ('q'),
                                          ('r'),
                                          ('s'),
                                          ('t'),
                                          ('u')) r2 (c1))
           'result10'
       END;
...