繁体   English   中英

PL/pgSQL 列名与变量相同

[英]PL/pgSQL column name the same as variable

我是 plpgsql 的新手,我正在尝试创建函数来检查表中是否存在某个值,如果不存在则添加一行。

CREATE OR REPLACE FUNCTION hire(
    id_pracownika integer,
    imie character varying,
    nazwisko character varying,
    miasto character varying,
    pensja real)
  RETURNS TEXT AS
$BODY$
DECLARE
wynik TEXT;
sprawdzenie INT;
BEGIN
sprawdzenie = id_pracownika;
IF EXISTS (SELECT id_pracownika FROM pracownicy WHERE id_pracownika=sprawdzenie) THEN
wynik = "JUZ ISTNIEJE";
RETURN wynik;
ELSE
INSERT INTO pracownicy(id_pracownika,imie,nazwisko,miasto,pensja)
VALUES (id_pracownika,imie,nazwisko,miasto,pensja);
wynik = "OK";
RETURN wynik;   
END IF;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

问题是我收到错误,说id_pracownika是一个列名和一个变量。

如何在这种上下文中指定“id_pracownika”是指列名?

假设id_pracownika是表的PRIMARY KEY 或者至少定义了UNIQUE (如果它不是NOT NULL ,则 NULL 是一个极端情况。)

SELECTINSERT

您的函数是“SELECT 或 INSERT”的另一种实现UPSERT问题的一个变体,它在并发写入负载时比看起来更复杂。 看:

在 Postgres 9.5 或更高版本中使用 UPSERT

在 Postgres 9.5 或更高版本中,使用Postgres Wiki 中的UPSERT ( INSERT ... ON CONFLICT ... )详细信息。 这种新语法做得很干净

CREATE OR REPLACE FUNCTION hire(
        _id_pracownika integer
      , _imie varchar
      , _nazwisko varchar
      , _miasto varchar
      , _pensja real)
  RETURNS text
  LANGUAGE plpgsql AS
$func$
BEGIN
   INSERT INTO pracownicy
          ( id_pracownika, imie, nazwisko, miasto, pensja)
   VALUES (_id_pracownika,_imie,_nazwisko,_miasto,_pensja);
   ON     CONFLICT DO NOTHING
   RETURNING 'OK';

   IF NOT FOUND THEN
      RETURN 'JUZ ISTNIEJE';
   END IF;
END
$func$;

表限定列名以在必要时消除歧义。 (您也可以使用函数名称作为函数参数的前缀,但这很容易变得尴尬。)
但是INSERT的目标列表中的列名可能不是表限定的。 (无论如何都不要模棱两可。)

最好避免这种先验的歧义,这样就不容易出错。 有些人(包括我)喜欢通过在所有函数参数和变量前面加上下划线来做到这一点。

如果您也确实需要一个列名作为函数参数名,避免命名冲突的一种方法是在函数内使用ALIAS ALIAS实际上有用的罕见情况之一。

或者按顺序位置引用函数参数:在这种情况下, id_pracownika$1

如果所有其他方法都失败了,您可以通过设置#variable_conflict来决定什么优先。 看:

还有更多:

在 Postgres 9.4 或更早版本中没有 UPSERT

...
   IF EXISTS (SELECT FROM pracownicy p
             WHERE  p.id_pracownika = hire.id_pracownika) THEN
      RETURN 'JUZ ISTNIEJE';
   ELSE
      INSERT INTO pracownicy(id_pracownika,imie,nazwisko,miasto,pensja)
      VALUES (hire.id_pracownika,hire.imie,hire.nazwisko,hire.miasto,hire.pensja);
    
      RETURN 'OK';
   END IF;
...

EXISTS表达式中, SELECT列表无关紧要。 SELECT id_pracownikaSELECT 1 ,甚至SELECT 1/0 - 都是一样的。 只需使用一个空的SELECT列表。 只有任何符合条件的行的存在才重要。 看:

这是我测试的一个示例,我使用 EXECUTE 运行选择并将其结果放入游标中,使用动态列名。

1. 创建表:

create table people (
  nickname varchar(9),
  name varchar(12),
  second_name varchar(12),
  country varchar(30)
  );

2. 创建函数:

CREATE OR REPLACE FUNCTION fun_find_people (col_name text, col_value varchar)
RETURNS void AS
$BODY$
DECLARE
    local_cursor_p refcursor;
    row_from_people RECORD;

BEGIN
    open local_cursor_p FOR
        EXECUTE 'select * from people where '|| col_name || ' LIKE ''' || col_value || '%'' ';

    raise notice 'col_name: %',col_name;
    raise notice 'col_value: %',col_value;

    LOOP
        FETCH local_cursor_p INTO row_from_people; EXIT WHEN NOT FOUND;

        raise notice 'row_from_people.nickname: %',  row_from_people.nickname ;
        raise notice 'row_from_people.name: %', row_from_people.name ;
        raise notice 'row_from_people.country: %', row_from_people.country;
    END LOOP;
END;
$BODY$ LANGUAGE 'plpgsql'

3. 运行函数select fun_find_people('name', 'Cristian'); select fun_find_people('country', 'Chile'); select fun_find_people('name', 'Cristian'); select fun_find_people('country', 'Chile');

从 Erwin Brandstetter 的答案中获得启发。

CREATE OR REPLACE FUNCTION test_upsert(
        _parent_id int, 
        _some_text text)
  RETURNS text
  LANGUAGE plpgsql AS
$func$
DECLARE a text;
BEGIN
   INSERT INTO parent_tree (parent_id, some_text)
   VALUES (_parent_id,_some_text)
   ON     CONFLICT DO NOTHING
   RETURNING 'ok' into a;
   return a;

   IF NOT FOUND THEN
        return 'JUZ ISTNIEJE';
   END IF;
END
$func$;
  1. 按照埃尔文的回答。 我让a变量保存返回类型文本。
  2. 如果冲突什么都不做,那么该函数将不返回任何内容。 例如,已经有parent_id = 10 ,那么结果如下:
test_upsert
------------

(1 row)
  1. 不确定的用法:

     IF NOT FOUND THEN return 'JUZ ISTNIEJE'; END IF;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM