当前位置: 首页 > 面试题库 >

PostgreSQL-根据从另一个表中的选择插入行,并使用新插入的行在该表中更新FK

乐正秦斩
2023-03-14
问题内容

我正在两个表之间进行数据迁移(拆分出一个相关的表)。现有表为reminders,它具有一start列和一个dateset_id指向新dateset表的新添加的列,该表也具有一start列。对于每一行reminders,我要INSERT一个新的行datesetstart复制价值,并UPDATE在相应的行reminders与新插入的datesetID。

这是我尝试过的SQL:

WITH inserted_datesets AS (
  INSERT INTO dateset (start)
  SELECT start FROM reminder
  RETURNING reminder.id AS reminder_id, id AS dateset_id
)
UPDATE reminder
SET dateset_id = ids.dateset_id
FROM inserted_datesets AS ids
WHERE reminder.id = ids.reminder_id

我收到一个错误missing FROM-clause entry for table "reminder",因为我reminder.id在该RETURNING子句中包括了该列,但实际上没有为插入选择它。这是有道理的,但我不知道如何修改查询以执行所需的操作。我缺少一种完全不同的方法吗?


问题答案:

有几种解决问题的方法。

1.临时添加一列

正如其他人提到的那样,简单的方法是将列临时添加reminder_id到中dateset。原装填充它IDsreminder表。使用它reminderdateset表连接。删除临时列。

2.何时启动是唯一的

如果该start列的值是唯一的,则可以通过将remindertable与该dateset列上的表连接起来而无需额外的start列。

INSERT INTO dateset (start)
SELECT start FROM reminder;

WITH
CTE_Joined
AS
(
    SELECT
        reminder.id AS reminder_id
        ,reminder.dateset_id AS old_dateset_id
        ,dateset.id AS new_dateset_id
    FROM
        reminder
        INNER JOIN dateset ON dateset.start = reminder.start
)
UPDATE CTE_Joined
SET old_dateset_id = new_dateset_id
;

3.启动时不是唯一的

即使在这种情况下,也可以在没有临时列的情况下进行操作。主要思想如下。让我们看一下这个例子:

我们有两个reminder具有相同start值和ID 3和7的行:

reminder
id    start         dateset_id
3     2015-01-01    NULL
7     2015-01-01    NULL

将它们插入之后dateset,将生成新的ID,例如1和2:

dateset
id    start
1     2015-01-01
2     2015-01-01

我们如何链接这两行并不重要。最终结果可能是

reminder
id    start         dateset_id
3     2015-01-01    1
7     2015-01-01    2

或者

reminder
id    start         dateset_id
3     2015-01-01    2
7     2015-01-01    1

这两个变体都是正确的。这带给我们以下解决方案。

只需首先插入所有行。

INSERT INTO dateset (start)
SELECT start FROM reminder;

start知道列不是唯一的情况下匹配/联接列上的两个表。通过添加ROW_NUMBER和连接两列来“使它变得唯一”
。可以使查询更短,但是我明确说明了每个步骤:

WITH
CTE_reminder_rn
AS
(
    SELECT
        id
        ,start
        ,dateset_id
        ,ROW_NUMBER() OVER (PARTITION BY start ORDER BY id) AS rn
    FROM reminder
)
,CTE_dateset_rn
AS
(
    SELECT
        id
        ,start
        ,ROW_NUMBER() OVER (PARTITION BY start ORDER BY id) AS rn
    FROM dateset
)
,CTE_Joined
AS
(
    SELECT
        CTE_reminder_rn.id AS reminder_id
        ,CTE_reminder_rn.dateset_id AS old_dateset_id
        ,CTE_dateset_rn.id AS new_dateset_id
    FROM
        CTE_reminder_rn
        INNER JOIN CTE_dateset_rn ON 
            CTE_dateset_rn.start = CTE_reminder_rn.start AND
            CTE_dateset_rn.rn = CTE_reminder_rn.rn
)
UPDATE CTE_Joined
SET old_dateset_id = new_dateset_id
;

我希望可以从代码中清楚地知道它的作用,尤其是当您将它与没有的简单版本进行比较时ROW_NUMBER。显然,即使start是唯一的,复杂的解决方案也可以使用,但效率却不如简单的解决方案。

此解决方案假定dateset在此过程之前为空。



 类似资料:
  • 问题内容: 我有两个表,具有相同的架构- 我想将test2表中的值插入到test1中,但是如果具有相同主键的行已经存在,请对其进行更新。我知道在mysql中,您可以使用ON DUPLICATE KEY UPDATE做类似的事情- 但是我不知道如何使用另一个表中的SELECT来执行上述查询。我正在寻找的是表格查询- 该查询显然是无效的。如果有人可以从中提出有效的查询,我将不胜感激。 问题答案: 这应

  • null 目前我可以完成第1和第2步,但是(假设可以完成)我无法获得第3步中“not exist”的语法。 这是我当前的代码:

  • 问题内容: 我是SQL的初学者,对Transact-SQL不太了解。 我意识到这是一个新手问题,但是我正在寻找一个简单的解决方案。 我有一个带有一些列()的表。 主表 我想从该表中选择数据并插入到其他两个表中。 第一桌 是来自的前三个字符的组合 第一个表中的数据按的前三个字符和客户代码分组 第二张桌子 那么,如何通过使用SQL选择主表的行来插入第一张表和第二张表呢? 感谢您的所有答复。 问题答案:

  • 问题内容: 考虑以下两个表 表格1 表2 如何在表2没有表1的ID的情况下从表2将数据插入表1? 换句话说,我想要以下结果: 表2 问题答案: 在你的问题的措辞有点混乱,因为你首先要问 我如何将数据插入 表1 从表2中 但此时你显示了预期的结果 表2 。 现在,如果您想使用table2中不存在的s将table1中的行插入table2中,则可以使用这种方式 这是 SQLFiddle 演示 或者 这是

  • 问题内容: 显然,以下是不正确的。 我得到的价值: SQL查询: MySQL说: 1093-您无法在FROM子句中指定目标表’aTable’用于更新 因此,我试图制作一个位图表,每一行对应一个位,并具有一个“ map”值。 要插入表中,我不想执行两个查询,而是想执行一个查询。我应该怎么做? 没有人对此发表评论,但是由于我正在尝试制作位图,因此应该是* 2而不是^ 2,是我的错误,请注意,这就是为什

  • 问题内容: 我要寻找正确的语法和方式做直接从SQL如下:插入或更新(如果数据已经内部存在)从包含在数据与两者都具有相同的复合主键。 这两个表的定义为: 将定期删除并填充。 因为相同的定义,但将包含数据的更多的行和我需要的是从插入从未见过值入,并更新现有的行。 我曾经做过这种插入,但是我不知道如何处理更新和复合主键: 编辑:我正在使用 SQL Server 9.00.5000 编辑:另一种受MERG