Есть три способа, о которых я мог подумать. Два очень просты, один сложный, но относится к (variable1, variable2)
.
CASE
использованию (легко) JSONB
использованию (легко) TYPE
использование (сложное)
ПЕРВЫЙ ВАРИАНТ: CASE
использование
Это самый простой, но не очень оптимизированный вариант.
Когда вы используете SELECT vals INTO vars
, вы должны иметь одинаковое количество значений и переменных. Таким образом, в этом варианте вам понадобится CASE
для каждого значения.
-- 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;$$
Если переменная изменится на '2', то результат будет 3 и 4.
Здесь Вы изменяете свой код
CASE var
WHEN 1 THEN
variable1, variable2
WHEN 2 THEN
variable3, variable4
на
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
Если вы добавляете больше переменных, вы добавляете больше случаев.
ВТОРОЙ ВАРИАНТ: JSONB
использование
Этот вариант является наилучшим подходом, поскольку вам не нужно кодировать многие предложения CASE
и не нужно создавать дополнительные шаги для процесса.
По сути, вы используете переменную JSONB
, в которой есть все необходимые переменные, например:
{
"val1": 1,
"val2": 2
}
И вот как вы это делаете:
-- 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;$$
Обратите внимание, что здесь вы вставляете JSON объект в переменную типа JSONB
. Одинаковое количество переменных в vals.
Поскольку JSON действительно гибкий объект, для добавления дополнительных переменных вам просто нужно настроить JSON соответственно.
В PostgreSQL лучше всего использовать JSONB
вместо простого JSON
. В руководстве говорится:
Тип данных json хранит точную копию входного текста, функции обработки которого должны обрабатываться при каждом выполнении; в то время как данные jsonb хранятся в разложенном двоичном формате, что делает их немного медленнее для ввода из-за дополнительных издержек преобразования, но значительно быстрее для обработки, так как повторный анализ не требуется. jsonb также поддерживает индексирование, что может быть существенным преимуществом.
ТРЕТИЙ ВАРИАНТ: TYPE
использование
Этот параметр является более сложным, поскольку мы вводим в RECORD
местности. Да, (data1,data2)
в PostgreSQL - это RECORD
. Что такое запись? Проще говоря, ROW
не имеет структуры данных.
Что означает RECORD
? Ну, чтобы было понятно, когда вы создаете таблицу, например:
CREATE TABLE data(val1 integer,val2 integer);
Если вы хотите вставить данные в таблицу «данные», вы должны вставить запись , поэтому, когда вы делаете:
INSERT INTO data(val1,val2) VALUES (1,2);
Вы вставляете RECORD
(1,2)
в данные.
ПРИМЕЧАНИЕ , что 1 и 2 заключены в скобки (1,2)
. Итак, когда вы пишете (variable1,variable2)
, вы создаете RECORD
, который содержит переменную 1 и переменную 2.
В соответствии с руководством
Переменные записи аналогичны переменным типа строки, но они не имеют предопределенной структуры ...
RECORD не является истинным типом данных, а только заполнителем.
Вот проблема. У RECORD
нет структуры, поэтому PostgreSQL не знает, как ее анализировать. Когда вы используете INSERT INTO
ваше говорящее PostgreSQL структуру, поэтому запись принимает структуру таблицы (предыдущий пример).
Когда вы делаете:
SELECT
CASE var
WHEN 1 THEN
(variable1, variable2)
WHEN 2 THEN
(variable3, variable4)
Вы выбираете RECORD
.
Чтобы упростить его, если вы сделаете SELECT (1,2)
, вы получите:
row (record)
------------
(1,2)
Как назначить структуру для ROW? ну, вы используете SELECT
, FOR
или TYPE
. SELECT
и FOR
используются аналогично INSERT INTO
, вы знаете структуру данных. В этом случае нет ссылки, поэтому использование TYPE
обязательно.
В PostgreSQL вы можете создавать свои персональные типы данных. Следовательно, вы можете сделать:
CREATE TYPE mytype AS (val1 integer, val2 integer);-- execute only once
Подобно таблице, вы можете создать ТИП один раз, и ТИП станет доступным во всей базе данных. Чтобы удалить тип, который вы просто делаете DROP TYPE mytype;
mytype
имеет два значения, необходимые для переменных, например, таблицу, TYPE
может иметь любые "столбцы" с любыми типами данных.
Теперь, если вы сделаете SELECT (1,2)::mytype
, вы получите:
row (record)
------------
(1,2)
Все еще ряд, потому что PostgreSQL не знает, как его проанализировать.
Но если вы сделаете SELECT * FROM (VALUES(1,2)) AS mytype(val1,val2);
вы получите
val1 | val2
------+------
1 | 2
Это потому, что вы говорите PostgreSQL, как его анализировать (обратите внимание на использование VALUES
).
Это показывает, что не так просто присвоить структуру строке записи. Но это возможно, как показано ниже:
-- 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;$$
Ключевая часть использует ARRAY.
При выполнении:
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
Вы получаете эту ошибку:
ERROR: missing FROM-clause entry for table "x"
PostgreSQL не знает, как его анализировать, поэтому вы говорите PostgreSQL, чтобы получить его через массив.
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
Это выводит:
val1 | val2
------+------
1 | 2
Проблема с этой опцией заключается в том, что TYPE
, который вы создаете, является stati c, поэтому, если вам придется изменить его, вам придется отбросить тип и создать его снова.
Но вот как ты делаешь это. Второй вариант - лучший, более современный подход.