我想用它来构造unique_key。但我不想明确提供架构名称。有什么方法可以搞清楚吗?
CREATE OR REPLACE FUNCTION is_value_free(_header_id integer, _value varchar)
RETURNS BOOLEAN AS
$$
BEGIN
RETURN NOT EXISTS (
SELECT header_id, value
FROM myschema.mytable
WHERE value LIKE _value AND header_id != _header_id
LIMIT 1);
END;
$$ LANGUAGE plpgsql;
ALTER TABLE mytable
ADD CONSTRAINT uniq_value CHECK (is_value_free(header_id,value))
如果我这样做,它必须有效:
set search_path = schema1;
CREATE FUNCTION AS ABOVE
set search_path = schema2;
INSERT INTO schema1.mytable(id, header_id, value)
VALUES (1,1,'a'); -- Should be ok
INSERT INTO schema1.mytable(id, header_id, value)
VALUES (1,2,'a'); -- Should violate error
考虑具有相同表结构的多个模式。
Edt:2012.05.16-1533 以此表为例: Header_table:id serial Snapshot_table:id serial,header_id int(FK到头表),值varchar
id id | header_id | value
1 1 | 1 | a
2 2 | 1 | a
3 3 | 2 | b
4 | 3 | b
等。使用header_id 3进行记录会违反unique_key
这是指:Unique constraint on one column with excluding row with same values in other
Edt:20120516-2356 添加一些测试脚本(对不起,我不知道如何加入文件)
drop schema if exists s1 cascade;
drop schema if exists s2 cascade;
drop schema if exists tp cascade;
create schema s1;
create schema s2;
create schema tp; -- Temporary schema to hold insert function
-- SCHEMA 1 --
set search_path = s1;
-- * * * header table * * *
CREATE TABLE th1 (
id SERIAL NOT NULL,
constraint th1_pk_id PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
-- * * * snapshot table * * *
CREATE TABLE ts1 (
id SERIAL NOT NULL,
header_id INTEGER NOT NULL,
version INTEGER NOT NULL,
value VARCHAR NOT NULL,
CONSTRAINT ts1_pk_id PRIMARY KEY (id),
CONSTRAINT ts1_header_id_fk FOREIGN KEY (header_id) REFERENCES th1(id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE
)
WITH (
OIDS=FALSE
);
CREATE OR REPLACE FUNCTION is_value_free(_header_id integer, _value varchar)
RETURNS BOOLEAN AS
$$
DECLARE
b boolean;
BEGIN
RAISE INFO ' ---- CHECK UNIQUE FUNCTION ----';
RAISE INFO 'Search_path: %', current_schema();
RAISE INFO 'Function caled schema: %', 's1';
SELECT NOT EXISTS (
SELECT 1
FROM ts1
WHERE value LIKE _value AND header_id != _header_id
LIMIT 1) INTO b;
RAISE INFO 'Result: %', b;
RETURN b;
END;
$$ LANGUAGE plpgsql;
ALTER TABLE ts1
ADD CONSTRAINT uniq_value CHECK (is_value_free(header_id,value));
CREATE OR REPLACE FUNCTION logSchema() RETURNS TRIGGER AS $$
BEGIN
RAISE INFO 'Call on schema: %', 's1';
RETURN new;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER logSchemaTrigger
BEFORE INSERT OR UPDATE ON ts1
FOR EACH ROW EXECUTE PROCEDURE logSchema();
-- SCHEMA2 --
set search_path = s2;
-- * * * header table * * *
CREATE TABLE th1 (
id SERIAL NOT NULL,
constraint th1_pk_id PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
-- * * * snapshot table * * *
CREATE TABLE ts1 (
id SERIAL NOT NULL,
header_id INTEGER NOT NULL,
version INTEGER NOT NULL,
value VARCHAR NOT NULL,
CONSTRAINT ts1_pk_id PRIMARY KEY (id),
CONSTRAINT ts1_header_id_fk FOREIGN KEY (header_id) REFERENCES th1(id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE
)
WITH (
OIDS=FALSE
);
CREATE OR REPLACE FUNCTION is_value_free(_header_id integer, _value varchar)
RETURNS BOOLEAN AS
$$
DECLARE
b boolean;
BEGIN
RAISE INFO ' ---- CHECK UNIQUE FUNCTION ----';
RAISE INFO 'Search_path: %', current_schema();
RAISE INFO 'Function caled schema: %', 's2';
SELECT NOT EXISTS (
SELECT 1
FROM ts1
WHERE value LIKE _value AND header_id != _header_id
LIMIT 1) INTO b;
RAISE INFO 'Result: %', b;
RETURN b;
END;
$$ LANGUAGE plpgsql;
ALTER TABLE ts1
ADD CONSTRAINT uniq_value CHECK (is_value_free(header_id,value));
CREATE OR REPLACE FUNCTION logSchema() RETURNS TRIGGER AS $$
BEGIN
RAISE INFO 'Actual schema: %', 's2';
RETURN new;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER logSchemaTrigger
BEFORE INSERT OR UPDATE ON ts1
FOR EACH ROW EXECUTE PROCEDURE logSchema();
-- INSERT PREPARE DATA --
-- insert function to handle error
CREATE OR REPLACE FUNCTION tp.insert_data_test(_schemaname name, _header_id integer, _version integer, _value varchar)
RETURNS VOID AS
$$
DECLARE
schemaname name;
b boolean;
BEGIN
RAISE INFO '==== NEW INSERT COMMAND ====';
SELECT _schemaname into schemaname;
IF schemaname IS NULL THEN
SELECT current_schema() INTO schemaname;
end if;
RAISE INFO 'Search_path: %', schemaname;
RAISE INFO 'Inserting data: %, %, %', _header_id, _version, _value;
BEGIN
EXECUTE 'SELECT NOT EXISTS ( SELECT 1 FROM ' ||(select case when schemaname is null then 'null' else schemaname end)|| '.th1 WHERE id = ' || quote_literal(_header_id) || ' LIMIT 1)' INTO b;
IF (SELECT b) THEN
EXECUTE 'INSERT INTO ' || (select case when schemaname is null then 'null' else schemaname end) || '.th1 VALUES(' || quote_literal(_header_id) ||')';
END IF;
EXECUTE 'INSERT INTO ' || (select case when schemaname is null then 'null' else schemaname end) || '.ts1(header_id, version, value) VALUES( ' || quote_literal(_header_id) || ',' || quote_literal(_version) ||','|| quote_literal(_value) ||')';
EXCEPTION WHEN others THEN
RAISE INFO 'Insert error: % %', SQLERRM, SQLSTATE;
RETURN;
END;
RAISE INFO 'Insert succesfull';
END;
$$ LANGUAGE plpgsql;
-- Wiht no current schema --
set search_path = default;
SELECT tp.insert_data_test('s1',1,0,'a');
SELECT tp.insert_data_test('s2',1,0,'b');
/* IF you do this above with before set search_path its go fine, but if you do insert from newone query thats drop:
ERROR: relation "ts1" does not exist
LINE 3: FROM ts1
^
QUERY: SELECT NOT EXISTS (
SELECT 1
FROM ts1
WHERE value LIKE _value AND header_id != _header_id
LIMIT 1)
CONTEXT: PL/pgSQL function "is_value_free" line 3 at RETURN
********** Chyba **********
ERROR: relation "ts1" does not exist
Stav SQL: 42P01
Kontext:PL/pgSQL function "is_value_free" line 3 at RETURN
*/
-- Insert data with corect schema --
set search_path = s1;
SELECT tp.insert_data_test(null,1,1,'a2');
set search_path = s2;
SELECT tp.insert_data_test(null,1,1,'b2');
-- Insert data with incorect schema --
set search_path = s2;
SELECT tp.insert_data_test('s1',1,2,'a3');
set search_path = s1;
SELECT tp.insert_data_test('s2',1,2,'b3');
-- TEST DATA (Should for all violate unique_key)--
-- Wiht no current schema --
set search_path = default;
SELECT tp.insert_data_test('s1',2,0,'a');
SELECT tp.insert_data_test('s2',2,0,'b');
-- Wiht corect current schema --
set search_path = s1;
SELECT tp.insert_data_test(null,3,0,'a');
set search_path = s2;
SELECT tp.insert_data_test(null,3,0,'b');
-- Wiht incorect current schema --
set search_path = s2;
SELECT tp.insert_data_test('s1',4,0,'a');
set search_path = s1;
SELECT tp.insert_data_test('s2',4,0,'b');
drop schema if exists s1 cascade;
drop schema if exists s2 cascade;
drop schema if exists tp cascade;
美国东部时间:2012.05.28:1937
托盘并在数据库中找到它(我之前没有看到)
CREATE OR REPLACE FUNCTION is_value_free(_header_id integer, _value varchar)
RETURNS BOOLEAN AS
$BODY$
BEGIN
RETURN SELECT NOT EXISTS
(
SELECT NULL
FROM mytable
WHERE value LIKE $2
AND header_id != $1
);
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION schema1.is_value_free(integer, character varying) SET search_path=schema1, public;
但是我需要在创建数据库函数时使用相同的代码并使用postgre函数从数据库中获取定义(如备份...)
答案 0 :(得分:4)
CREATE OR REPLACE FUNCTION is_value_free(_header_id integer, _value varchar)
RETURNS BOOLEAN AS
$$
SELECT NOT EXISTS
(
SELECT NULL
FROM mytable
WHERE value LIKE $2
AND header_id != $1
);
$$ LANGUAGE sql
SET search_path FROM CURRENT;
不需要EXISTS
半联接LIMIT 1
且SELECT
项无关紧要。
请注意,您的唯一功能不可交换,因此表格内容将取决于记录的插入顺序。
<强>更新强>
DROP SCHEMA IF EXISTS s1 CASCADE;
DROP SCHEMA IF EXISTS s2 CASCADE;
CREATE SCHEMA s1;
CREATE SCHEMA s2;
SET search_path = s1;
DROP TABLE IF EXISTS mytable;
CREATE TABLE mytable (id bigserial primary key, header_id integer not null, value text);
CREATE OR REPLACE FUNCTION is_value_free(_header_id integer, _value varchar)
RETURNS BOOLEAN AS
$$
SELECT NOT EXISTS
(
SELECT NULL
FROM mytable
WHERE value LIKE $2
AND header_id != $1
);
$$ LANGUAGE sql
-- Below is the most important clause
SET search_path FROM CURRENT;
ALTER TABLE mytable
ADD CONSTRAINT uniq_value CHECK (is_value_free(header_id,value));
SET search_path = s2;
DELETE
FROM s1.mytable;
INSERT INTO s1.mytable(id, header_id, value)
VALUES (1,1,'a'); -- Should be ok
INSERT INTO s1.mytable(id, header_id, value)
VALUES (2,2,'a'); -- Should violate error