Zastanawiałem się, czy możliwe jest użycie wyrażenia przypadków w instrukcji wybranej w Postgres, gdzie piszę wartości wielu wartości jednocześnie.

Na przykład:

DO
$$
DECLARE
    var int := 1;
    val1 int;
BEGIN
    SELECT
    CASE var
    WHEN 1 THEN
        variable1, variable2
    WHEN 2 THEN
        variable3, variable4
    INTO 
        val1, val2
    FROM mytable;
$$

Rzecz, to działa dobrze przy użyciu tego:

DO
$$
DECLARE
    var int := 1;
    val1 int;
    val2 int;
BEGIN
    SELECT
    CASE var
    WHEN 1 THEN
        variable1
    WHEN 2 THEN
        variable3
    INTO 
        val1
    FROM mytable;
$$

Wiem, że mogę po prostu przesunąć obudowę poza instrukcją SELECT i po prostu napisz dwa wybierz opcję, ale wydaje się, że wydaje się więcej, aby pisać wtedy rozwiązanie, które chcę.

Kolejna rzecz, której próbowałem, była:

DO
$$
DECLARE
    var int := 1;
    val1 int;
BEGIN
    SELECT
    CASE var
    WHEN 1 THEN
        (variable1, variable2)
    WHEN 2 THEN
        (variable3, variable4)
    INTO 
        val1, val2
    FROM mytable;
$$

Wydaje się, że to wydaje się pisać (zmienna1, zmienna2) do VAL1 i nie powiedzie się z powodu niewłaściwego DataType.

Myślę, że z ostatnim rozwiązaniem mogłem napisać wartości w tablicy, ale potrzebuję ich w oddzielnych zmiennych.

Wszelkie wskazówki są mile widziane.

1
MaGr 12 marzec 2020, 17:46

1 odpowiedź

Najlepsza odpowiedź

Istnieją trzy sposoby, o których mogłem pomyśleć. Dwa są naprawdę łatwe, jeden jest złożony, ale związany z (variable1, variable2).

  1. CASE Wykorzystanie (łatwe)
  2. JSONB Wykorzystanie (łatwe)
  3. TYPE Wykorzystanie (kompleks)

pierwsza opcja: CASE Wykorzystanie

Ten jest najłatwiejszy, ale nie tak naprawdę zoptymalizowany.

Gdy używasz SELECT vals INTO vars musi mają taką samą ilość Vals i Vars. Tak więc w tej opcji potrzebowałbyś CASE dla każdej wartości.

-- CASE QUERY
DO $$
DECLARE
-- control var
    var integer := 1;
-- result vars
    var1 integer := 1;
    var2 integer := 2;
    var3 integer := 3;
    var4 integer := 4;
-- final values
    val1 integer;
    val2 integer;
BEGIN
    SELECT
        CASE var -- CASE for val1
            WHEN 1 THEN var1
            WHEN 2 THEN var3 END,
        CASE var -- CASE for val2
            WHEN 1 THEN var2 
            WHEN 2 THEN var4 END
    INTO val1,val2;

    RAISE NOTICE '%',val1; -- outputs: 1
    RAISE NOTICE '%',val2; -- outputs: 2
END;$$

Jeśli var zmienia się na "2", wyjście byłoby 3 i 4.

Tutaj zmieniasz swój kod

CASE var
    WHEN 1 THEN
        variable1, variable2
    WHEN 2 THEN
        variable3, variable4

Do

CASE var -- CASE for val1
    WHEN 1 THEN variable1
    WHEN 2 THEN variable3 END,
CASE var -- CASE for val2
    WHEN 1 THEN variable2
    WHEN 2 THEN variable4 END

Jeśli dodasz więcej zmiennych, dodasz więcej przypadków.

Druga opcja: JSONB Wykorzystanie

Ta opcja jest najlepszym podejściem, ponieważ nie musisz kodułować wielu CASE klauzul, a nie musisz tworzyć dodatkowych kroków do procesu.

Zasadniczo używasz zmiennej JSONB, która ma wszystkie zmienne, których potrzebujesz:

{
   "val1": 1,
   "val2": 2
}

I oto jak to robisz:

-- USING JSONB
DO $$
DECLARE
-- control var
    var integer := 1;
-- result vars
    var1 integer := 1;
    var2 integer := 2;
    var3 integer := 3;
    var4 integer := 4;
-- JSON var that will have val1 and val2 data
    jsonvar jsonb;
BEGIN
    SELECT CASE var 
            WHEN 1 THEN CAST('{"val1":'||var1||',"val2":'||var2||'}' as jsonb)
            WHEN 2 THEN CAST('{"val1":'||var3||',"val2":'||var4||'}' as jsonb) END
    INTO jsonvar;

    RAISE NOTICE '%',jsonvar->>'val1'; -- outputs: 1
    RAISE NOTICE '%',jsonvar->>'val2'; -- outputs: 2
END;$$

Zauważ, że tutaj wkładasz obiekt JSON w zmienną, która jest typu JSONB. Ta sama ilość Vars w Vals.

Ponieważ JSON jest naprawdę elastycznym obiektem, aby dodać więcej zmiennych, musisz odpowiednio dostosować JSON.

W PostgreSQL najlepiej użyć JSONB zamiast zwykłej {x1}}. Podręcznik stanowi:

Typ danych JSON przechowuje dokładną kopię tekstu wejściowego, które funkcje przetwarzania muszą uregulować na każdym wykonaniu; Podczas gdy dane JSONB są przechowywane w rozkładanym formacie binarnym, który sprawia, że nieco wolniejsze do wejścia z powodu dodanej konwersji nad głową, ale znacznie szybciej do przetworzenia, ponieważ nie jest potrzebny nie jest wymagany. JSONB obsługuje również indeksowanie, co może być znaczącą przewagą.

trzecia opcja: TYPE Wykorzystanie

Ta opcja jest bardziej złożoną opcją, ponieważ wchodzimy w terenie RECORD. Tak, (data1,data2) w PostgreSQL to RECORD. Co to jest rekord? W prostych słowach jest ROW, który nie ma struktury danych.

Co oznacza RECORD? Cóż, aby to było jasne, gdy utworzysz tabelę, na przykład:

CREATE TABLE data(val1 integer,val2 integer);

Jeśli chcesz wstawić dane do tabeli "Data", musisz wstawić rekord , więc kiedy to zrobisz:

INSERT INTO data(val1,val2) VALUES (1,2);

Twoje wkładanie RECORD (1,2) do danych.

Uwaga , że 1 i 2 są wewnątrz nawiasów (1,2). Kiedy piszesz (variable1,variable2) twoja robienie RECORD, która zawiera zmienną1 i zmienną2.

Zgodnie z instrukcją

Rekordowe zmienne są podobne do zmiennych typu wiersza, ale nie mają predefiniowanej struktury ...

Rekord nie jest prawdziwym typem danych, tylko zastępczem.

Oto problem. A RECORD nie ma struktury, więc postgresql nie wie, jak go przeanalizować. Kiedy używasz INSERT INTO Twój mówienie PostgreSQL strukturę, więc rekord przyjmuje strukturę tabeli (poprzedni przykład).

Kiedy robisz:

SELECT
    CASE var
    WHEN 1 THEN
        (variable1, variable2)
    WHEN 2 THEN
        (variable3, variable4)

Wybieranie RECORD.

Aby go uprościć, jeśli to zrobisz SELECT (1,2)

row (record)
------------
(1,2)

Jak przypisać strukturę do rzędu? Cóż, używasz SELECT, FOR lub używasz TYPE. SELECT i FOR są używane podobne do INSERT INTO, znasz strukturę danych. W tym przypadku nie ma odniesienia, więc użycie TYPE jest obowiązkowe.

W PostgreSQL możesz utworzyć swoje dane osobowe. Dlatego możesz zrobić:

CREATE TYPE mytype AS (val1 integer, val2 integer);-- execute only once

Podobnie jak w tabeli, możesz utworzyć typ raz, a typ jest dostępny w całej bazie danych. Aby upuścić typ, który po prostu wykonasz DROP TYPE mytype;

mytype ma dwie wartości potrzebne do zmiennych, takich jak tabela, TYPE może mieć dowolne "kolumny" z dowolnymi typami danych.

Teraz, jeśli to zrobisz SELECT (1,2)::mytype, otrzymasz:

row (record)
------------
(1,2)

Wciąż wiersz, ponieważ postgresql nie wie, jak go przeanalizować.

Ale jeśli to zrobisz SELECT * FROM (VALUES(1,2)) AS mytype(val1,val2);

 val1 | val2
------+------
    1 |    2

Dzieje się tak dlatego, że opowiadasz postgresql Jak przewidzieć go (zwróć uwagę na użycie VALUES).

To pokazuje, że nie jest to łatwe do przypisania struktury do rekordowego wiersza. Ale jest możliwy, jak pokazano poniżej:

-- USING TYPES
-- Requires mytype created
DO $$
DECLARE
-- control var
    var integer := 1;
-- result vars
    var1 integer := 1;
    var2 integer := 2;
    var3 integer := 3;
    var4 integer := 4;
-- final values
    val1 integer;
    val2 integer;
BEGIN
    SELECT x[1].val1,x[1].val2
    FROM(
        SELECT ARRAY(
            SELECT CASE var
                WHEN 1 THEN (var1,var2)::mytype 
                WHEN 2 THEN (var3,var4)::mytype END
        )::mytype[] AS x
    )dataset
    INTO val1,val2;

    RAISE NOTICE '%',val1; -- outputs: 1
    RAISE NOTICE '%',val2; -- outputs: 2
END;$$

Część klucza używa tablicy.

Po wykonaniu:

SELECT x.val1,x.val2
        FROM(
            SELECT CASE 1
                WHEN 1 THEN (1,2)::mytype
                WHEN 2 THEN (3,4)::mytype END AS X
        )dataset

Otrzymujesz ten błąd:

ERROR:  missing FROM-clause entry for table "x"

PostgreSQL nie wie, jak przewidzieć go, więc mówisz PostgreSQL, aby dostać go przez tablicę.

SELECT
x[1].val1,x[1].val2
FROM(
    SELECT ARRAY(
        SELECT CASE 1
           WHEN 1 THEN (1,2)::mytype
           WHEN 2 THEN (4,5)::mytype END
    )::mytype[] AS x
) dataset

To daje:

 val1 | val2
------+------
    1 |    2

Problem z tą opcją jest to, że tworzysz TYPE jest statyczne, więc jeśli musisz go zmienić, musiałbyś upuścić typ i utrzymać go ponownie.

Ale tak to robisz. Druga opcja jest najlepsza, a także bardziej nowoczesna aproach.

1
Dan 13 marzec 2020, 23:21