【问题标题】:SQL query to search for a record in one table and replace it with multiple records from another tableSQL查询在一个表中搜索记录并将其替换为另一表中的多条记录
【发布时间】:2020-03-17 20:54:20
【问题描述】:

我有两个表 - 包和子包:

CREATE TABLE Package (
    Sequence int PRIMARY KEY,
    Package int,
    Mnemonic char(3),
    MnemonicValue int
);

CREATE TABLE SubPackage (
    Sequence int PRIMARY KEY,
    SubPackage int,
    Mnemonic char(3),
    MnemonicValue int
);

INSERT INTO Package (Sequence, Package, Mnemonic, MnemonicValue)
VALUES (1, 111, 'XXX', 0), (2, 111, 'SUB', 153), (3, 111, 'DDD', 30), (4, 111, 'YYY', 20), (5, 111, 'ZZZ', 1000);

INSERT INTO SubPackage (Sequence, SubPackage, Mnemonic, MnemonicValue)
VALUES (1, 153, 'AAA', 20), (2, 153, 'BBB', 1000), (3, 153, 'CCC', 30);

要求是在包表中搜索助记符“SUB”,并将SUB记录替换为“子包”表中映射的助记符值(153)的记录,并重新排序序列值,如[结果][2] 表。

我尝试使用更新语句为:

UPDATE package
SET    Mnemonic = subpackage.Mnemonic
FROM   package
       INNER JOIN subpackage
       ON package.MnemonicValue = subpackage.SubPackage

但这会将包表中的 SUB 记录替换为子包表中的仅 AAA 记录。我希望将 SUB 记录替换为子包表中的所有记录,并在新表中对其重新排序,如结果表所示。

想要的结果:

Sequence | Particular | Mnemonic | MnemonicValue

       1 |         111|       XXX|             0        
       2 |         111|       AAA|            20
       3 |         111|       BBB|          1000
       4 |         111|       CCC|            30
       5 |         111|       DDD|            30
       6 |         111|       YYY|            20
       7 |         111|       ZZZ|          1000

【问题讨论】:

  • 您标记了 MySQL、SQL Server 和 Oracle?它们是 3 个独立的 RDBMS - 您真正感兴趣的是哪个?请调整您的标签。
  • 对于 SO 问题,图片也是可取的,请将数据格式化为文本。
  • @Max 。 . .我删除了不一致的数据库标签。这似乎需要merge,这是相当依赖于数据库的,因此适当的数据库标签非常重要。
  • 现在你已经删除了格式?请使用问题中的代码格式选项以可读的方式布局代码和数据。
  • @GordonLinoff 我已经添加了数据库标签

标签: mysql sql sql-update sql-insert


【解决方案1】:

您可以使用left join 来获得您想要的结果:

select
    p.sequence,
    p.package,
    coalesce(s.mnemonic, p.mnemonic) mnemonic,
    coalesce(s.mnemonic_value, p.mnemonic_value) mnemonic_value
from package p
left join sub_package s 
    on  p.mnemonic = 'SUB'
    and p.mnemonic_value = s.sub_package

“替换”新行有点复杂。插入新行,然后删除原始行可能会更简单(您可以在事务中执行此操作):

start transaction;

insert into package(sequence, package, mnemonic, mnemonic_value)
select
    p.sequence,
    p.package,
    coalesce(s.mnemonic, p.mnemonic),
    coalesce(s.mnemonic_value, p.mnemonic_value)
from package p
left join sub_package s 
    on  p.mnemonic = 'SUB'
    and p.mnemonic_value = s.sub_package;

delete from package where mnemonic = 'SUB';

commit;

【讨论】:

  • 包表中的记录重复,顺序也很乱
【解决方案2】:

我不认为您可以更新 Package 表以获得您想要的确切结果,即问题是在您的示例中您重新排序 Sequence 列。

无论如何,这里是 SQL 脚本(基于 GMB 的回答),它将生成您想要获得的结果:

select
    ROW_NUMBER() OVER (ORDER BY p.Sequence) as Sequence,
    p.Package,
    coalesce(s.Mnemonic, p.Mnemonic) Mnemonic,
    coalesce(s.MnemonicValue, p.MnemonicValue) MnemonicValue
from Package p
left join SubPackage s 
    on p.MnemonicValue = s.SubPackage
order by p.Sequence

但是,AFAIK 它只适用于 MySQL 8

这是link to SQLFiddle,但要注意它是针对 Postgres 的(因为 SQLFiddle 不支持 MySQL 8)。

如果您使用的是早期版本的 MySQL,您可以try to emulate row_number function

【讨论】:

    猜你喜欢
    • 2021-01-26
    • 1970-01-01
    • 2017-02-01
    • 1970-01-01
    • 2022-09-24
    • 1970-01-01
    • 2015-11-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多