PostgreSQL - 使用子查询更新多个列值

发布于 2024-12-05 02:12:35 字数 1039 浏览 1 评论 0原文

我需要能够使用子查询的结果更新表上的多个列。一个简单的示例如下所示 -

UPDATE table1
SET (col1, col2) =
  ((SELECT MIN (ship_charge), MAX (ship_charge) FROM orders))
WHERE col4 = 1001; 

如何在 PostgreSQL 中执行此操作?

感谢您的任何提示!

更新:我很抱歉使示例对于我的实际用例来说过于简单。下面的查询更准确 -

UPDATE table1
SET    (TOTAL_MIN_RATE, TOTAL_MAX_RATE) = (SELECT AVG(o.MIN_RATE), AVG(o.MAX_RATE)
                           FROM   ORDR o INNER JOIN table2 ba ON (o.PAY_ACCT_ID = ba.ACCT_ID) 
                                         INNER JOIN table3 mb ON (ba.BANK_ID = mb.BANK_ID)
                               WHERE  ba.CNTRY_ID = table1.CNTRY_ID AND 
                                              o.STUS_CD IN ('01','02','03','04','05','06') AND
                                  ((o.FRO_CRNCY_ID = table1.TO_CRNCY_ID AND o.TO_CRNCY_ID = table1.FRO_CRNCY_ID) OR
                                   (o.TO_CRNCY_ID = table1.TO_CRNCY_ID AND o.FRO_CRNCY_ID = table1.FRO_CRNCY_ID))   
                               GROUP BY ba.CNTRY_ID)

I need to be able to update multiple columns on a table using the result of a subquery. A simple example will look like below -

UPDATE table1
SET (col1, col2) =
  ((SELECT MIN (ship_charge), MAX (ship_charge) FROM orders))
WHERE col4 = 1001; 

How can I do this in PostgreSQL ?

Thanks for any tips!

UPDATE: I apologize for making the sample too simple for my actual use-case. The query below is more accurate -

UPDATE table1
SET    (TOTAL_MIN_RATE, TOTAL_MAX_RATE) = (SELECT AVG(o.MIN_RATE), AVG(o.MAX_RATE)
                           FROM   ORDR o INNER JOIN table2 ba ON (o.PAY_ACCT_ID = ba.ACCT_ID) 
                                         INNER JOIN table3 mb ON (ba.BANK_ID = mb.BANK_ID)
                               WHERE  ba.CNTRY_ID = table1.CNTRY_ID AND 
                                              o.STUS_CD IN ('01','02','03','04','05','06') AND
                                  ((o.FRO_CRNCY_ID = table1.TO_CRNCY_ID AND o.TO_CRNCY_ID = table1.FRO_CRNCY_ID) OR
                                   (o.TO_CRNCY_ID = table1.TO_CRNCY_ID AND o.FRO_CRNCY_ID = table1.FRO_CRNCY_ID))   
                               GROUP BY ba.CNTRY_ID)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

惟欲睡 2024-12-12 02:12:36

这不是最有效的方法,但很简单:

UPDATE table1 SET
col1 = (SELECT MIN (ship_charge) FROM orders),
col2 = (SELECT MAX (ship_charge) FROM orders)
WHERE col4 = 1001; 

This isn't the most efficient way to do this, but it's simple:

UPDATE table1 SET
col1 = (SELECT MIN (ship_charge) FROM orders),
col2 = (SELECT MAX (ship_charge) FROM orders)
WHERE col4 = 1001; 
独夜无伴 2024-12-12 02:12:36

一种选择(但不是唯一的选择)是使用两个单独的子查询:

update table1
set col1 = (select min(ship_charge) from orders),
    col2 = (select max(ship_charge) from orders)
where col4 = 1001;

来自 PostgreSQL 9.0的更新精细手册

根据标准,列列表语法应允许从单个行值表达式(例如子选择)分配列列表:

更新帐户 SET (contact_last_name, contact_first_name) =
(从销售人员中选择姓氏、名字
 WHERE salesmen.id = 账户.sales_id);

目前尚未实现 - 源必须是独立表达式的列表。

One option (but not the only one) is to use two separate sub-queries:

update table1
set col1 = (select min(ship_charge) from orders),
    col2 = (select max(ship_charge) from orders)
where col4 = 1001;

From the fine manual for PostgreSQL 9.0's UPDATE:

According to the standard, the column-list syntax should allow a list of columns to be assigned from a single row-valued expression, such as a sub-select:

UPDATE accounts SET (contact_last_name, contact_first_name) =
(SELECT last_name, first_name FROM salesmen
 WHERE salesmen.id = accounts.sales_id);

This is not currently implemented — the source must be a list of independent expressions.

最美的太阳 2024-12-12 02:12:36

当您没有简单的子选择时,使用 UPDATE FROM 是一个很好的解决方案。在此UPDATE中,我想将photos表的event_profile_id设置为照片集的所有者(事件配置文件也是所有者)照片属于.

UPDATE photos
SET event_profile_id=photos_and_events.event_profile_id
FROM (
  SELECT
    ph.id photo_id,
    pr.id event_profile_id
  FROM photos ph, profiles pr, photo_sets ps
  WHERE ph.main_photo_set_id=ps.id AND ps.owner_profile_id=pr.id
) AS photos_and_events
WHERE photos.id=photos_and_events.photo_id;

Using UPDATE FROM is a good solution when you don't have simple subselects. In this UPDATE I wanted to set the event_profile_id of the photos table to be the owner (event profiles are owners too) of the photo set the photo belongs to.

UPDATE photos
SET event_profile_id=photos_and_events.event_profile_id
FROM (
  SELECT
    ph.id photo_id,
    pr.id event_profile_id
  FROM photos ph, profiles pr, photo_sets ps
  WHERE ph.main_photo_set_id=ps.id AND ps.owner_profile_id=pr.id
) AS photos_and_events
WHERE photos.id=photos_and_events.photo_id;
旧时模样 2024-12-12 02:12:36

正如官方文档所说:您可以使用标准更新PostgreSQL更新概要

UPDATE table
    SET { column = { expression | DEFAULT } |
          ( column [, ...] ) = ( { expression | DEFAULT } [, ...] ) } [, ...]
    [ FROM from_list ]
    [ WHERE condition ]

所以你可以使用这样的写法:

UPDATE table1
SET TOTAL_MIN_RATE = subQuery."minRate",
 TOTAL_MAX_RATE = subQuery.maxRate
FROM
    (
        SELECT
            AVG (o.MIN_RATE) AS minRate,
            AVG (o.MAX_RATE) AS maxRate
        FROM
            ORDR o
        INNER JOIN table2 ba ON (o.PAY_ACCT_ID = ba.ACCT_ID)
        INNER JOIN table3 mb ON (ba.BANK_ID = mb.BANK_ID)
        WHERE
            ba.CNTRY_ID = table1.CNTRY_ID
        AND o.STUS_CD IN (
            '01',
            '02',
            '03',
            '04',
            '05',
            '06'
        )
        AND (
            (
                o.FRO_CRNCY_ID = table1.TO_CRNCY_ID
                AND o.TO_CRNCY_ID = table1.FRO_CRNCY_ID
            )
            OR (
                o.TO_CRNCY_ID = table1.TO_CRNCY_ID
                AND o.FRO_CRNCY_ID = table1.FRO_CRNCY_ID
            )
        )
        GROUP BY
            ba.CNTRY_ID
    ) subQuery;

或者更简单的方法:

UPDATE table1
SET (
    TOTAL_MIN_RATE,
    TOTAL_MAX_RATE
) = (
    SELECT
        AVG (o.MIN_RATE) AS minRate,
        AVG (o.MAX_RATE) AS maxRate
    FROM
        ORDR o
    INNER JOIN table2 ba ON (o.PAY_ACCT_ID = ba.ACCT_ID)
    INNER JOIN table3 mb ON (ba.BANK_ID = mb.BANK_ID)
    WHERE
        ba.CNTRY_ID = table1.CNTRY_ID
    AND o.STUS_CD IN (
        '01',
        '02',
        '03',
        '04',
        '05',
        '06'
    )
    AND (
        (
            o.FRO_CRNCY_ID = table1.TO_CRNCY_ID
            AND o.TO_CRNCY_ID = table1.FRO_CRNCY_ID
        )
        OR (
            o.TO_CRNCY_ID = table1.TO_CRNCY_ID
            AND o.FRO_CRNCY_ID = table1.FRO_CRNCY_ID
        )
    )
    GROUP BY
        ba.CNTRY_ID
);

As the official document says: you can use the standard update Synopsis of PostgreSQL update

UPDATE table
    SET { column = { expression | DEFAULT } |
          ( column [, ...] ) = ( { expression | DEFAULT } [, ...] ) } [, ...]
    [ FROM from_list ]
    [ WHERE condition ]

So you can use write like this:

UPDATE table1
SET TOTAL_MIN_RATE = subQuery."minRate",
 TOTAL_MAX_RATE = subQuery.maxRate
FROM
    (
        SELECT
            AVG (o.MIN_RATE) AS minRate,
            AVG (o.MAX_RATE) AS maxRate
        FROM
            ORDR o
        INNER JOIN table2 ba ON (o.PAY_ACCT_ID = ba.ACCT_ID)
        INNER JOIN table3 mb ON (ba.BANK_ID = mb.BANK_ID)
        WHERE
            ba.CNTRY_ID = table1.CNTRY_ID
        AND o.STUS_CD IN (
            '01',
            '02',
            '03',
            '04',
            '05',
            '06'
        )
        AND (
            (
                o.FRO_CRNCY_ID = table1.TO_CRNCY_ID
                AND o.TO_CRNCY_ID = table1.FRO_CRNCY_ID
            )
            OR (
                o.TO_CRNCY_ID = table1.TO_CRNCY_ID
                AND o.FRO_CRNCY_ID = table1.FRO_CRNCY_ID
            )
        )
        GROUP BY
            ba.CNTRY_ID
    ) subQuery;

Or a more simple way:

UPDATE table1
SET (
    TOTAL_MIN_RATE,
    TOTAL_MAX_RATE
) = (
    SELECT
        AVG (o.MIN_RATE) AS minRate,
        AVG (o.MAX_RATE) AS maxRate
    FROM
        ORDR o
    INNER JOIN table2 ba ON (o.PAY_ACCT_ID = ba.ACCT_ID)
    INNER JOIN table3 mb ON (ba.BANK_ID = mb.BANK_ID)
    WHERE
        ba.CNTRY_ID = table1.CNTRY_ID
    AND o.STUS_CD IN (
        '01',
        '02',
        '03',
        '04',
        '05',
        '06'
    )
    AND (
        (
            o.FRO_CRNCY_ID = table1.TO_CRNCY_ID
            AND o.TO_CRNCY_ID = table1.FRO_CRNCY_ID
        )
        OR (
            o.TO_CRNCY_ID = table1.TO_CRNCY_ID
            AND o.FRO_CRNCY_ID = table1.FRO_CRNCY_ID
        )
    )
    GROUP BY
        ba.CNTRY_ID
);
oО清风挽发oО 2024-12-12 02:12:36

我需要在一个表上进行多次插入,从两个表中获取数据,而它们之间没有公共列,并忽略已经存在的记录。

以下 sql 在 Postgresql 11 上进行了测试,尽管它在 v9+ 上应该可以正常工作:

WITH permission_info AS (
    SELECT id
    FROM permission
    WHERE permission."key" LIKE 'prefix_for_admin_%'
), role_info AS (
    SELECT id 
    FROM role
    WHERE role."name" = 'Admin'
)
INSERT INTO role_permission_table
(
    role_id,
    permission_id
)
    SELECT role_info.id, permission_info.id FROM role_info, permission_info

ON CONFLICT DO NOTHING
;

I needed to do multiple inserts on a table taking the data from two tables without common columns between them and ignoring records already present.

The following sql was tested on Postgresql 11, althought it should work fine on v9+:

WITH permission_info AS (
    SELECT id
    FROM permission
    WHERE permission."key" LIKE 'prefix_for_admin_%'
), role_info AS (
    SELECT id 
    FROM role
    WHERE role."name" = 'Admin'
)
INSERT INTO role_permission_table
(
    role_id,
    permission_id
)
    SELECT role_info.id, permission_info.id FROM role_info, permission_info

ON CONFLICT DO NOTHING
;
挽清梦 2024-12-12 02:12:35

如果您想避免两个子选择,可以像这样重写查询:

UPDATE table1
  SET col1 = o_min, col2 = o_max
FROM ( 
    SELECT min(ship_charge) as o_min, 
           max(ship_charge) as o_max
    FROM orders
) t 
WHERE col4 = 1001

如果ship_charge没有索引,这应该比两个子选择更快。如果ship_charge被索引,它可能不会产生很大的差异


编辑

从Postgres 9.5开始,这也可以写成:

UPDATE table1
  SET (col1, col2) = (SELECT min(ship_charge), max(ship_charge) FROM orders)
WHERE col4 = 1001

If you want to avoid two subselects, the query can be rewritten like this:

UPDATE table1
  SET col1 = o_min, col2 = o_max
FROM ( 
    SELECT min(ship_charge) as o_min, 
           max(ship_charge) as o_max
    FROM orders
) t 
WHERE col4 = 1001

If ship_charge is not indexed, this should be faster than two subselects. If ship_charge is indexed, it probably doesn't make a big difference


Edit

Starting with Postgres 9.5 this can also be written as:

UPDATE table1
  SET (col1, col2) = (SELECT min(ship_charge), max(ship_charge) FROM orders)
WHERE col4 = 1001
雨的味道风的声音 2024-12-12 02:12:35
UPDATE table1
SET
    col1 = subquery.min_value,
    col2 = subquery.max_value
FROM
(

    SELECT
        1001 AS col4,
        MIN (ship_charge) AS min_value,
        MAX (ship_charge) AS max_value
    FROM orders
) AS subquery
WHERE table1.col4 = subquery.col4

如果您想一次更新 table1 中的多行,您还可以在子查询中返回多行。

UPDATE table1
SET
    col1 = subquery.min_value,
    col2 = subquery.max_value
FROM
(

    SELECT
        1001 AS col4,
        MIN (ship_charge) AS min_value,
        MAX (ship_charge) AS max_value
    FROM orders
) AS subquery
WHERE table1.col4 = subquery.col4

You can also return multiple rows in the subquery if you want to update multiple rows at once in table1.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文