我想知道是否有可能在postgres的SELECT语句中使用CASE表达式,在该语句中我一次写入多个值。
例如:
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;
$$
事情是使用它时效果很好:
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;
$$
我知道我可以将CASE移到SELECT语句之外,只编写两个SELECT语句,但这似乎比我想要的解决方案要写的多。
我尝试的另一件事是:
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;
$$
但是这似乎将(variable1,variable2)写入val1,并且由于数据类型错误而失败。
我猜用最后一个解决方案,我可以将值写入数组,但是我需要在单独的变量中使用它们。
感谢任何提示。
我可以考虑三种方式。有两个很简单,一个很复杂,但与(variable1, variable2)
有关。
CASE
用法(简单)JSONB
用法(简单)TYPE
用法(复杂)首选:CASE
用法
这是最简单但不是真正优化的选项。
当使用SELECT vals INTO vars
时,必须具有相同数量的val和var。因此,在此选项中,每个值都需要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;$$
如果var更改为'2',则输出将为3和4。
您在这里更改代码
CASE var
WHEN 1 THEN
variable1, variable2
WHEN 2 THEN
variable3, variable4
to
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
的变量中。将相同数量的var转换为val。
因为JSON实际上是一个灵活的对象,所以要添加更多变量,您只需要相应地调整JSON。
在PostgreSQL中,最好使用JSONB
而不是普通的JSON
。手册指出:
json数据类型存储输入文本的精确副本,其中处理功能必须在每次执行时重新解析;而jsonb数据以分解后的二进制格式存储,因此速度稍慢由于增加了转换开销而无法输入,但速度要快得多流程,因为不需要重新解析。 jsonb还支持索引,这可能是一个显着的优势。
第三选项:TYPE
用法
此选项是更复杂的选项,因为我们输入了RECORD
地形。是的,PostgreSQL中的(data1,data2)
是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)
时,将制作包含变量1和变量2的RECORD
。
根据手册
记录变量类似于行类型变量,但它们没有预定义的结构 ...
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
类似于表,您一次可以创建一个TYPE,并且TYPE在整个数据库中都可用。要删除类型,只需执行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;$$
关键部分是使用阵列。
执行时:
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
是静态的,因此,如果必须更改它,则必须删除该类型并再次创建它。
但是您就是这样做的。第二种选择是最好的,也是一种更现代的方法。