PostgresQL:使用键值而不是两个列表插入

PostgresQL: Insert with key-value instead of two lists

PostgresQL 允许您使用两个列表进行 INSERT,一个是字段名,另一个是值。

INSERT INTO products (product_no, name, price) VALUES (1, 'Cheese', 9.99);

对于长列表,很难确定您在哪个列表索引上。有没有办法通过在值旁边指定列名来插入,即键值对?注意:这与 hstore.

不同

INSERT INTO products (product_no => 1, name => 'Cheese', price => 9.99);

常规DML是不可能的。

替代方案:

使用值列表来缩短 DML:

INSERT INTO products (product_no, name, price) VALUES
  (1, 'Cheese', 9.99),
  (2, 'Sausages', 9.99),
  ...;

或者创建可以使用参数指定执行的函数:

create or replace function insert_product(
  in product_no products.product_no%type, 
  in name products.name%type, 
  in price products.price%type) returns products.product_no%type as $$
  insert into products(product_no, name, price) values (product_no, name, price) returning product_no;
$$ language sql;

select insert_product(1, 'Mashrooms', 1.99); -- Parameters by order 
select insert_product(product_no := 2, name := 'Cheese', price := 9.99); -- Parameters by name
select insert_product(product_no := 3, price := 19.99, name := 'Sosages'); -- Order does mot matter

我创建了一个供我使用。下面将 json 作为输入并创建动态 SQL 查询并执行相同的查询。

示例用法

create table employee(name character varying(20), address character varying(100), basic integer);

--sample call-1
call insert_into(true, 'employee', '{
    "name"      : "''Ravi Kumar''",
    "address"   : "''#1, 2nd Cross, Bangalore''",
    "basic"     : 35000
}',
'');

--sample call-2
call insert_into(true, 'employee', '{
    "name"      : "eo.name",
    "address"   : "eo.address",
    "basic"     : "eo.basic"
}',
'
from employee_old eo
');

程序

CREATE or REPLACE PROCEDURE insert_into(
    debug BOOLEAN,
    tableName TEXT,
    jsonTxt json,
    fromWhere TEXT
)
LANGUAGE plpgsql
as $$
DECLARE
    field TEXT;
    fieldQuery TEXT;
    valueQuery TEXT;
    finalQuery TEXT;
    noOfRecords INT;
BEGIN 
    IF debug THEN
        raise notice 'preparing insert query';
    END IF;
    
    fieldQuery := CONCAT('INSERT INTO ', tableName, '(', E'\n');
    valueQuery := CONCAT('SELECT ', E'\n');
    
    FOR field IN SELECT * FROM json_object_keys(jsonTxt)
    LOOP
        fieldQuery := CONCAT(fieldQuery, field, E',\n');
        valueQuery := CONCAT(valueQuery, json_extract_path_text(jsonTxt, field), E',\n');
        
    END LOOP;
    fieldQuery := RTRIM(fieldQuery, E',\n');
    fieldQuery := CONCAT(fieldQuery, ')');
    
    valueQuery := RTRIM(valueQuery, E',\n');
    
    finalQuery := CONCAT(fieldQuery, E'\n', valueQuery, E'\n', fromWhere, ';');
    
    IF debug THEN
        RAISE NOTICE 'query:: %',  finalQuery;
    END IF;
    
    EXECUTE finalQuery;
    get diagnostics noOfRecords = row_count;
    RAISE NOTICE 'Inserted:: %',  noOfRecords;
END
$$;