postgres-简化数据库操作

时间:2019-01-22 13:43:55

标签: postgresql


我在下面的表中需要用表2的最新值更新表1,而无需创建中间临时表。
表1

| environment | division | item | item_cost |
| ----------- | -------- | ---- | --------- |
| 'local' | 'first' | 'item-U' | 0 |
| 'local-queue' | 'first' | 'item-U' | 0 |
| 'denmark' | 'first' | 'item-U' | 0 |
| 'local' | 'first' | 'item-C' | 0 |
| 'local-queue' | 'first' | 'item-C' | 0 |
| 'denmark' | 'first' | 'item-C' | 0 |
| 'local' | 'second' | 'item-E' | 0 |
| 'local' | 'second' | 'item-L' | 0 |

表2

| environment | division | item | item_cost |
| ----------- | -------- | ---- | --------- |
| 'denmark' | 'second' | 'item-E' | 1666 |
| 'local' | 'second' | 'item-E' | 4444 |
| 'denmark' | 'first' | 'item-U' | 18080 |
| 'denmark' | 'first' | 'item-U' | 18079 |
| 'local' | 'first' | 'item-U' | 55555 |

是否可以将Table-2合并到Table-1中,使Table-2的最新值低于输出?

| environment | division | item | item_cost |
| ----------- | -------- | ---- | --------- |
| 'local' | 'first' | 'item-U' | 55555 |
| 'local-queue' | 'first' | 'item-U' | 0 |
| 'denmark' | 'first' | 'item-U' | 18080 |
| 'local' | 'first' | 'item-C' | 0 |
| 'local-queue' | 'first' | 'item-C' | 0 |
| 'denmark' | 'first' | 'item-C' | 0 |
| 'local' | 'second' | 'item-E' | 4444 |
| 'local' | 'second' | 'item-L' | 0 |

我有一个传统的方法,可以创建一个临时表,然后查找并更新。 我只是想知道是否有一种方法可以在不创建临时表的情况下即时获得所需的输出。
表2中的某些条目可能不需要在输出中显示。

谢谢。

1 个答案:

答案 0 :(得分:0)

您需要考虑使用SQL进行基于集合的操作,并假设它总是可能的。使用两个集合,并尝试通过遍历集合1来更新集合2而不是使用SQL一次完成所有操作,这是一个常见错误。

我可以回答您的问题,但是由于至少两个原因,您的示例不清楚:

  • 每行的主键或唯一标识符是什么?如果没有定义,则无法合并2个列表。我以为是环境,部门和项目。但是您有2行都显示丹麦语,首先是表2中的item-U。
  • 您的“低于输出”是没有道理的。表2中第一个成本为1666的项目是否应该出现在最终输出中?

假设环境,部门和项目是唯一的,则这是合并两组数据的正确方法。尝试插入新记录,如果键已经存在,则更新该键的item_cost:

INSERT INTO table_1 (environment, division, item, item_cost)
SELECT environment, division, item, item_cost
FROM table_2
ON CONFLICT (environment, division, item)
DO UPDATE
SET item_cost = EXCLUDED.item_cost;

ON CONFLICT受Postgres 9.5+支持。

如果table_2行已经与table_1行相同,则最好执行以下稍微复杂一些的操作,以避免重复更新数据:

-- Only return rows that are actually different from what is already in table_1
WITH actual_data_diff AS
(SELECT environment, division, item, item_cost
FROM table_2
EXCEPT ALL
SELECT environment, division, item, item_cost
FROM table_1)

INSERT INTO table_1 (environment, division, item, item_cost)
SELECT environment, division, item, item_cost
FROM actual_data_diff
ON CONFLICT (environment, division, item)
DO UPDATE
SET item_cost = EXCLUDED.item_cost;

在报告环境中,您通常会获得大量的冗余写入,从而导致过多的膨胀和WAL流量,而上述模式仅允许进行实际更改,可以轻松避免这种情况。

有一个MERGE声明正在积极开发中,可能会与PG12一起发布。