【问题标题】:SQL Postgres Invalidate Rows that reference invalid Id'sSQL Postgres 使引用无效 ID 的行无效
【发布时间】:2015-08-05 01:39:49
【问题描述】:

我正在尝试创建一个存储过程,该过程将使包含另一个表中 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.idintegertable_b.idstext。目标是查看每个table_b.ids,如果它包含table_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;

一般的想法是我试图将table_b.ids 的每一行变成一个表,然后使用EXCEPT 运算符对table_a 来查看它是否有任何ID 是invalid。我收到的错误是:

ERROR:  syntax error at or near "SELECT"
LINE 1: ...able_b SET valid = FALSE WHERE COUNT(SELECT reg...

这不是很有帮助,因为它只是表明我没有正确的语法。这个查询可行吗?如果可以,您能告诉我哪里可能出错了吗?如果没有,是否有更简单甚至更复杂的方法来实现这一点?

样本数据:


CREATE TABLE table_b
(ids text, valid boolean);

INSERT INTO table_b
(ids, valid)
VALUES
('1,2,3'   ,  'T'),
('4,3,8'   ,  'T'),
('5,2,5,4' ,  'T'),
('7'       ,  'T'),
('6,8'     ,  'T'),
('9,7,2'   ,  'T');

CREATE TABLE table_a
(id integer, name text);

INSERT INTO table_a
(id, name)
VALUES
(1,'a'),
(2,'b'),
(3,'c'),
(4,'d'),
(5,'e'),
(6,'f'),
(7,'g'),
(8,'h');

【问题讨论】:

  • 以后请以易于转换为 SQL 表的形式提供您的示例数据。 CREATE TABLE 和 INSERTs 很好,但至少是 sqlfiddle.com 知道如何读取的表。

标签: sql database postgresql


【解决方案1】:
UPDATE table_b
SET valid = FALSE
WHERE EXISTS(
    SELECT regexp_split_to_table(table_b.ids) 
    EXCEPT SELECT id FROM table_a
);

您可以使用“存在”来检查行是否存在。以前的语法不正确,因为 count 不能这样使用。

【讨论】:

    【解决方案2】:

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

    您需要加入table_b,即使它是更新目标,因为您不能直接对更新目标表进行横向函数引用。

    【讨论】:

    • 这是非常糟糕的数据库设计,虽然它是代表生产数据库的示例,但我应该提到。感谢您的链接 - 一些非常有趣的阅读!
    • 这里只是一个问题 - AND a.id IS NULL 行在这里做什么?
    • 过滤掉左连接条件匹配的行。所以它只保留 a.id 没有对应 b.ids 条目的行。
    猜你喜欢
    • 2013-03-12
    • 2020-11-02
    • 1970-01-01
    • 2021-06-04
    • 2013-07-11
    • 2013-01-26
    • 1970-01-01
    • 2012-02-15
    • 2016-08-25
    相关资源
    最近更新 更多