递归的 PostgreSQL 查询用于更新列。

3

你好,我正在尝试使用SQL查询递归更新数据库列。

我有两个表modulemodule_dependency

第一个表module有列(带有示例数据):

id, name, state,
1, "website", "installed"
2, "purchase", "installed"
3, "crm", "installed"
4, "sale", "uninstalled"
5, "account", "installed"
6, "website_sale", "installed"
7, "purchase_bonus", "installed"
8, "website_blog", "installed"
9, "sale_discount", "installed"
10, "website_online", "installed"

第二个表格module_dependency包含如下列(附带示例数据):

 id | dependency_name | module_id 
----+-----------------+-----------
  1 | website_sale    |         1
  2 | sale_bonus      |         4
  3 | website_blog    |         1
  4 | sale_discount   |         4
  5 | website_online  |         1
  6 | crm             |         10
  7 | account         |         3

我需要将网站模块的状态更改为"升级",同时也需要更新其所有依赖模块。

我可以检查当前模块的状态:

SELECT * FROM module WHERE name = 'website' AND state = 'installed';

 id |  name   |   state   
----+---------+-----------
  1 | website | installed

为获取网站模块的所有依赖项,我使用以下查询语句:
SELECT m.name, md.dependency_name , md.module_id
FROM module m JOIN module_dependency md ON (m.id = md.module_id)
WHERE m.name = 'website' AND m.state = 'installed';

  name   | dependency_name | module_id 
---------+-----------------+-----------
 website | website_sale    |         1
 website | website_blog    |         1
 website | website_online  |         1

这意味着 website_sale, website_blogwebsite_online 依赖于模块ID为1的 website 模块。

主要问题在于 website_online 依赖于 crm 模块,而 crm 又依赖于 account 模块。

SELECT m.name, md.dependency_name , md.module_id
FROM module m JOIN module_dependency md ON (m.id = md.module_id)
WHERE m.name = 'website_online' AND m.state = 'installed';

      name      | dependency_name | module_id 
----------------+-----------------+-----------
 website_online | crm             |        10

SELECT m.name, md.dependency_name , md.module_id
FROM module m JOIN module_dependency md ON (m.id = md.module_id)
WHERE m.name = 'crm' AND m.state = 'installed';

 name | dependency_name | module_id 
------+-----------------+-----------
 crm  | account         |         3

我需要递归地将所有网站依赖项的状态更改为“升级”。更新后的行应该像这样:
id, name, state,
1, "website", "to upgrade"
3, "crm", "to upgrade"
5, "account", "to upgrade"
6, "website_sale", "to upgrade"
8, "website_blog", "to upgrade"
10, "website_online", "to upgrade"

您可以创建带有测试数据的表格:

CREATE TABLE module(id integer, name text, state text);
INSERT INTO module VALUES
(1, 'website', 'installed'),
(2, 'purchase', 'installed'),
(3, 'crm', 'installed'),
(4, 'sale', 'uninstalled'),
(5, 'account', 'installed'),
(6, 'website_sale', 'installed'),
(7, 'purchase_bonus', 'installed'),
(8, 'website_blog', 'installed'),
(9, 'sale_discount', 'installed'),
(10, 'website_online', 'installed');


CREATE TABLE module_dependency(id integer, dependency_name text, module_id integer);
INSERT INTO module_dependency VALUES
(1, 'website_sale', 1),
(2, 'sale_bonus', 4),
(3, 'website_blog', 1),
(4, 'sale_discount', 4),
(5, 'website_online', 1),
(6, 'crm', 10),
(7, 'account', 3);

我尝试编写递归查询,但没有成功。似乎出现了无限循环。如果我能获取模块表的所有模块ID,我可以简单地更新所选条目。

WITH RECURSIVE modules_to_upgrade AS
(
    SELECT id
    FROM module
    WHERE name = 'website'

        UNION ALL

    SELECT md.module_id
    FROM module_dependency md JOIN modules_to_upgrade mtu on mtu.id = md.module_id
)
select * from modules_to_upgrade;
1个回答

1

为了将递归部分链接回模块,似乎不能使用依赖项ID。

因此,必须使用名称。

WITH RECURSIVE rcte_modules_to_upgrade AS
(
    SELECT 
      m.id as module_id
    , m.name as module_name
    , md.id as dependency_id
    , md.dependency_name
    , m.id as base_module_id
    , 1 as depth
    FROM module m
    JOIN module_dependency md 
      ON md.module_id = m.id
    WHERE m.name = 'website'

    UNION ALL

    SELECT 
      m.id
    , m.name
    , md.id
    , md.dependency_name
    , rcte.base_module_id
    , rcte.depth + 1
    FROM rcte_modules_to_upgrade rcte
    JOIN module m
      ON m.name = rcte.dependency_name
    LEFT JOIN module_dependency md 
      ON md.module_id = m.id
)
select * 
from rcte_modules_to_upgrade;
module_id | module_name    | dependency_id | dependency_name | base_module_id | depth
--------: | :------------- | ------------: | :-------------- | -------------: | ----:
        1 | website        |             1 | website_sale    |              1 |     1
        1 | website        |             3 | website_blog    |              1 |     1
        1 | website        |             5 | website_online  |              1 |     1
        6 | website_sale   |          null | null            |              1 |     2
        8 | website_blog   |          null | null            |              1 |     2
       10 | website_online |             6 | crm             |              1 |     2
        3 | crm            |             7 | account         |              1 |     3
        5 | account        |          null | null            |              1 |     4
WITH RECURSIVE rcte_modules_to_upgrade AS
(
    SELECT 
      m.id as module_id
    , md.dependency_name
    FROM module m
    JOIN module_dependency md 
      ON md.module_id = m.id
    WHERE m.name = 'website'

    UNION ALL

    SELECT 
      m.id
    , md.dependency_name
    FROM rcte_modules_to_upgrade rcte
    JOIN module m
      ON m.name = rcte.dependency_name
    LEFT JOIN module_dependency md 
      ON md.module_id = m.id
)
update module
set state = 'to upgrade'
where id in (select distinct module_id 
             from rcte_modules_to_upgrade);
6 rows affected
select * from module order by id;
id | name           | state      
-: | :------------- | :----------
 1 | website        | to upgrade 
 2 | purchase       | installed  
 3 | crm            | to upgrade 
 4 | sale           | uninstalled
 5 | account        | to upgrade 
 6 | website_sale   | to upgrade 
 7 | purchase_bonus | installed  
 8 | website_blog   | to upgrade 
 9 | sale_discount  | installed  
10 | website_online | to upgrade 

db<>fiddle here


1
谢谢。起初我对这些id感到困惑。分层表通常具有整数作为子项和父项,都是外键。但这个不是。 - LukStorms

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接