【问题标题】:How do i SELECT multiple Values with postgreSQL INTO multiple variables Depending on a CASE?如何根据 CASE 使用 postgreSQL 将多个值选择为多个变量?
【发布时间】:2020-06-24 15:30:24
【问题描述】:

我想知道是否可以在 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 并且由于错误的数据类型而失败。

我猜最后一个解决方案可以将值写入数组,但我需要将它们放在单独的变量中。

感谢任何提示。

【问题讨论】:

    标签: postgresql select case


    【解决方案1】:

    我可以考虑三种方式。两个真的很简单,一个很复杂但与(variable1, variable2)相关。

    1. CASE 用法(简单)
    2. JSONBusage(简单)
    3. 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
    

    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 的变量中。将相同数量的 vars 转换为 vals。

    由于 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?好吧,你使用SELECTFOR,或者你使用TYPESELECTFOR 的使用与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;$$
    

    关键部分是使用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 通过一个 ARRAY 来获取它。

    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 是静态的,因此如果您必须更改它,您将不得不删除类型并重新创建它。

    但这就是你的做法。第二种选择是最好的,也是一种更现代的方法。

    【讨论】:

      猜你喜欢
      • 2013-08-09
      • 2014-07-05
      • 2014-10-04
      • 1970-01-01
      • 2011-03-09
      • 2013-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多