我正在使用PostgreSQL 9.2.4。
postgres =#select version();
version
-------------------------------------------------------------
PostgreSQL 9.2.4, compiled by Visual C++ build 1600, 64-bit
(1 row)
我的查询安全地执行插入。我需要的是我的函数应该返回除void数据类型之外的东西。像文本(“插入表格”)或整数(0-false,1-true)之类的东西,验证它是否被插入对我有用?
我需要一个函数的语法,该函数在插入完成后返回integer
或text
。用于验证目的。有什么方法可以解决这个问题吗?
答案 0 :(得分:3)
您很可能需要一个函数来返回text
,另一个函数返回integer
或返回boolean
的函数来表示成功。所有这些都是微不足道的,我会将您推荐给excellent manual on CREATE FUNCTION
或code examples in similar questions on SO。
如何编写一个返回文本或整数值的函数?
...从某种意义上说,一个返回类型为text
或integer
。不是那么微不足道,但也不是不可能的。关键词是:polymorphic types。
建立在这个简单的表格上:
CREATE TABLE tbl(
tbl_id int,
txt text,
nr int
);
此函数返回整数或文本(或任何其他类型,如果允许),具体取决于输入类型。
CREATE FUNCTION f_insert_data(_id int, _data anyelement, OUT _result anyelement)
RETURNS anyelement AS
$func$
BEGIN
CASE pg_typeof(_data)
WHEN 'text'::regtype THEN
INSERT INTO tbl(tbl_id, txt) VALUES(_id, _data)
RETURNING txt
INTO _result;
WHEN 'integer'::regtype THEN
INSERT INTO tbl(tbl_id, nr) VALUES(_id, _data)
RETURNING nr
INTO _result;
ELSE
RAISE EXCEPTION 'Unexpected data type: %', pg_typeof(_data)::text;
END CASE;
END
$func$
LANGUAGE plpgsql;
呼叫:
SELECT f_insert_data(1, 'foo'::text); -- explicit cast needed.
SELECT f_insert_data(1, 7);
一个函数返回TRUE
/ FALSE
以指示是否已插入行,只有一个输入参数类型不同:
CREATE FUNCTION f_insert_data2(_id int, _data anyelement)
RETURNS boolean AS
$func$
BEGIN
CASE pg_typeof(_data)
WHEN 'text'::regtype THEN
INSERT INTO tbl(tbl_id, txt) VALUES(_id, _data);
WHEN 'integer'::regtype THEN
INSERT INTO tbl(tbl_id, nr) VALUES(_id, _data);
ELSE
RAISE EXCEPTION 'Unexpected data type: >>%<<', pg_typeof(_data)::text;
END CASE;
IF FOUND THEN RETURN TRUE;
ELSE RETURN FALSE;
END IF;
END
$func$
LANGUAGE plpgsql;
对于大多数用途,输入类型可以替换为text
参数,可以转换为任何其他类型。
答案 1 :(得分:2)
听起来你通过创造一个更大的问题来解决问题。
根本不需要这个功能。通过检查每个DML查询返回的受影响的行数来在客户端执行此操作,或使用INSERT ... RETURNING
。
您没有提及您的客户端语言,因此这里是如何使用psycopg2
在Python中执行此操作。相同的方法适用于具有语法变化的其他语言。
#!/usr/bin/env python
import psycopg2
# Connect to the db
conn = psycopg2.connect("dbname=regress")
curs = conn.cursor()
# Set up the table to use
curs.execute("""
DROP TABLE IF EXISTS so17587735;
CREATE TABLE so17587735 (
id serial primary key,
blah text not null
);
""");
# Approach 1: Do the insert and check the rowcount:
curs.execute("""
INSERT INTO so17587735(blah) VALUES ('whatever');
""");
if curs.rowcount != 1:
raise Exception("Argh, insert affected zero rows, wtf?")
print("Inserted {0} rows as expected".format(curs.rowcount))
# Approach 2: Use RETURNING
curs.execute("""
INSERT INTO so17587735(blah) VALUES ('bored') RETURNING id;
""");
returned_rows = curs.fetchall();
if len(returned_rows) != 1:
raise Exception("Got unexpected row count {0} from INSERT".format(len(returned_rows)))
print("Inserted row id is {0}".format(returned_rows[0][0]))
在PL / PgSQL调用INSERT
的情况下,您可以使用the GET DIAGNOSTICS
command,FOUND
变量或RETURN QUERY EXECUTE INSERT ... RETURNING ...
。使用GET DIAGNOSTICS
:
CREATE OR REPLACE FUNCTION blah() RETURNS void AS $$
DECLARE
inserted_rows integer;
BEGIN
INSERT INTO some_table VALUES ('whatever');
GET DIAGNOSTICS inserted_rows = ROW_COUNT;
IF inserted_rows <> 1 THEN
RAISE EXCEPTION 'Failed to insert rows; expected 1 row, got %', inserted_rows;
END IF;
END;
$$ LANGUAGE plpgsql VOLATILE;
或者如果你必须返回值,并且由于某种原因必须使用PL / PgSQL:
CREATE OR REPLACE FUNCTION blah() RETURNS SETOF integer AS $$
BEGIN
RETURN QUERY EXECUTE INSERT INTO some_table VALUES ('whatever') RETURNING id;
END;
$$ LANGUAGE plpgsql VOLATILE;
(假设密钥为id
)
与:
相同CREATE OR REPLACE FUNCTION blah() RETURNS SETOF integer AS $$
INSERT INTO some_table VALUES ('whatever') RETURNING id;
$$ LANGUAGE sql;
或只是
INSERT INTO some_table VALUES ('whatever') RETURNING id;
换句话说:为什么要将它包装在函数中?这没有意义。只需使用RETURNING
或使用INSERT
的客户端驱动程序的受影响行计数检查行计数客户端。
答案 2 :(得分:0)
一个函数只能返回一种类型。在您的情况下,您可以创建一个包含两个字段的复合类型,一个整数和一个文本,然后返回。