SQL Postgres使引用无效Id的行无效';s
我试图创建一个存储过程,它将使包含另一个表中id的id引用的行无效。需要注意的是,要失效的行包含这些id的分组,这些id存储为逗号分隔的字符串。让我们看一下表:SQL Postgres使引用无效Id的行无效';s,sql,database,postgresql,Sql,Database,Postgresql,我试图创建一个存储过程,它将使包含另一个表中id的id引用的行无效。需要注意的是,要失效的行包含这些id的分组,这些id存储为逗号分隔的字符串。让我们看一下表: table_a table_b +----+------+ +---------+-------+ | id | name | | ids | valid | +----+------+ +---------+-------+ | 1 | a | | 1,2,
table_a table_b
+----+------+ +---------+-------+
| id | name | | ids | valid |
+----+------+ +---------+-------+
| 1 | a | | 1,2,3 | T |
| 2 | b | | 4,3,8 | T |
| 3 | c | | 5,2,5,4 | T |
| 4 | d | | 7 | T |
| 5 | e | | 6,8 | T |
| 6 | f | | 9,7,2 | T |
| 7 | g | +---------+-------+
| 8 | h |
+----+------+
在上面,您可以看到table_b
包含来自table_a
的id分组,您可以想象table_a.id
是一个integer
,而table_b.ids
是文本。目标是查看每个表\u b.id
,如果它包含一个在表\u a.id
中不存在的id,则将其有效性设置为false
我有很长一段时间没有使用过任何SQL
,也从未使用过PostgreSQL
,这就是我遇到如此困难的原因。我能想到的最接近的查询是无效的,但大致如下:
CREATE FUNCTION cleanup_records() AS $func$
BEGIN
UPDATE table_b
SET valid = FALSE
WHERE COUNT(
SELECT regexp_split_to_table(table_b.ids)
EXCEPT SELECT id FROM table_a
) > 0;
END;
$func$ LANGUAGE PLPGSQL;
一般的想法是,我试图将表b.id
的每一行转换为一个表,然后对表a
使用EXCEPT
操作符查看它是否有任何无效的ID
。我收到的错误是:
ERROR: syntax error at or near "SELECT"
LINE 1: ...able_b SET valid = FALSE WHERE COUNT(SELECT reg...
这不是很有帮助,因为它只是表明我没有正确的语法。这个问题可行吗?如果是的话,你能告诉我哪里出了问题吗?如果不是的话,有没有更简单甚至更复杂的方法来实现这一点
样本数据:
您可以使用“exists”检查是否存在行。前面的语法不正确,因为count
不能这样使用
这些id的分组存储为逗号分隔的字符串
不要那样做。这是一个非常糟糕的数据库设计,这也是您遇到问题的原因。见:
此外,还有一种比vkp更有效的查询方法。如果您这样做,那么您将为正在测试的每个ID拆分字符串。没有必要这样做。而是在扩展的ID列表表上进行连接
比如:
UPDATE table_b
SET valid = 'f'
FROM table_b b
CROSS JOIN regexp_split_to_table(b.ids, ',') b_ids(id)
LEFT JOIN table_a a ON (a.id = b_ids.id::integer)
WHERE table_b.ids = b.ids
AND a.id IS NULL
AND table_b.valid = 't';
您需要加入表b
,即使它是更新目标,因为您不能直接对更新目标表进行横向函数引用。以后请以易于转换为SQL表的形式提供示例数据。CREATETABLE和INSERTs很好,但至少有一个表知道如何读取。这是非常糟糕的数据库设计,尽管它是一个代表生产数据库的示例,我应该提到。谢谢你的链接-一些非常有趣的阅读!这里有个问题-和a.id为NULL的行在这里做什么?它过滤掉左连接条件匹配的行。因此,它只保留没有对应于a.id的b.id条目的行。
UPDATE table_b
SET valid = FALSE
WHERE EXISTS(
SELECT regexp_split_to_table(table_b.ids)
EXCEPT SELECT id FROM table_a
);
UPDATE table_b
SET valid = 'f'
FROM table_b b
CROSS JOIN regexp_split_to_table(b.ids, ',') b_ids(id)
LEFT JOIN table_a a ON (a.id = b_ids.id::integer)
WHERE table_b.ids = b.ids
AND a.id IS NULL
AND table_b.valid = 't';