Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL Postgres使引用无效Id的行无效';s_Sql_Database_Postgresql - Fatal编程技术网

SQL Postgres使引用无效Id的行无效';s

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,

我试图创建一个存储过程,它将使包含另一个表中id的id引用的行无效。需要注意的是,要失效的行包含这些id的分组,这些id存储为逗号分隔的字符串。让我们看一下表:

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';