sql - 如何保护表以避免重复数据

标签 sql postgresql database-design unique-constraint relational-division

我无法解决如何保护我的表以避免 attributes_positions 重复组合的问题。向您展示我的意思的最佳方式是下图

enter image description here

id_combination 列表示组合的数量。组合由 attributes_positions 组成。所以组合是 attributes_positions 的序列。

现在我将确保表不会插入完全相同的 attributes_positions 序列。

当然如果已经插入的组合包含一个额外的attributes_positions或者少一个插入组合也是可以的

图像我展示了重复和非重复组合之间的不同。

有什么方法可以做到这一点吗??有点像“更新前”。但是如何实现这个例子。我不太擅长高级 sql。 我尝试保护表的数据库是 postgresql 9.4

我将不胜感激

最佳答案

        -- The data
CREATE TABLE theset (
        set_id INTEGER NOT NULL PRIMARY KEY
        , set_name text UNIQUE
        );
INSERT INTO theset(set_id, set_name) VALUES
( 1, 'one'), ( 2, 'two'), ( 3, 'three'), ( 4, 'four');

CREATE TABLE theitem (
        item_id integer NOT NULL PRIMARY KEY
        , item_name text UNIQUE
        );
INSERT INTO theitem(item_id, item_name) VALUES
( 1, 'one'), ( 2, 'two'), ( 3, 'three'), ( 4, 'four'), ( 5, 'five');

CREATE TABLE set_item (
        set_id integer NOT NULL REFERENCES theset (set_id)
        , item_id integer NOT NULL REFERENCES theitem(item_id)
        , PRIMARY KEY (set_id,item_id)
        );
        -- swapped index is indicated for junction tables
CREATE UNIQUE INDEX ON set_item(item_id, set_id);

INSERT INTO set_item(set_id,item_id) VALUES
(1,1), (1,2), (1,3), (1,4),
(2,1), (2,2), (2,3), -- (2,4),
(3,1), (3,2), (3,3), (3,4), (3,5),
(4,1), (4,2), (4,4);

CREATE FUNCTION set_item_unique_set( ) RETURNS TRIGGER AS
$func$
BEGIN
IF EXISTS ( -- other set
        SELECT * FROM theset oth
        -- WHERE oth.set_id <> NEW.set_id -- only for insert/update
        WHERE TG_OP = 'DELETE' AND oth.set_id <> OLD.set_id
           OR TG_OP <> 'DELETE' AND oth.set_id <> NEW.set_id

        -- count (common) members in the two sets
        -- items not in common will have count=1
        AND NOT EXISTS (
                SELECT item_id FROM set_item x1
                WHERE (x1.set_id = NEW.set_id OR x1.set_id = oth.set_id )
                GROUP BY item_id
                HAVING COUNT(*) = 1
                )

        ) THEN
        RAISE EXCEPTION 'Not unique set';
        RETURN NULL;
ELSE
        RETURN NEW;
END IF;

END;
$func$ LANGUAGE 'plpgsql'
        ;

CREATE CONSTRAINT TRIGGER check_item_set_unique
        AFTER UPDATE OR INSERT OR DELETE
        -- BEFORE UPDATE OR INSERT
        ON set_item
        FOR EACH ROW
        EXECUTE PROCEDURE set_item_unique_set()
        ;

-- Test it
INSERT INTO set_item(set_id,item_id) VALUES(4,5); -- success
INSERT INTO set_item(set_id,item_id) VALUES(2,4); -- failure
DELETE FROM set_item WHERE set_id=1 AND item_id= 4; -- failure

注意:DELETE 情况也应该有触发器。


更新:添加了对DELETE

的处理

(删除的处理并不完美;想象一下删除集合中最后一个元素的情况)

关于sql - 如何保护表以避免重复数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42457269/

相关文章:

sql - 为了创建高质量的 Django 应用程序,我需要了解哪些关于数据库的知识?

java - Spring JPA :PropertyAccessException 1:. ..MethodInvocationException : .'driverClassName' . .. org/postgresql/Driver : Unsupported major. 次要版本 52.0

node.js - 如何使用 pg-promise 助手返回插入查询结果值

postgresql - 将 GNU R 连接到 PostgreSQL

database-design - 一维内非重叠范围的数据结构

sql - 数据库设计用户表拆分或单一

sql - 如果更新了多行,Microsoft SQL Server 2005 DB 的触发事件仅触发一次?

sql - 我可以在 'insert ... on duplicate update ...' 语句中重用绑定(bind)变量吗?

python - 关键字 CONSTRAINT 在此 CREATE TABLE 语句中的作用

mysql - 多表拆分记录和单表存储多条记录的优缺点是什么