【问题标题】:More efficient Update query (MS SQL Server 2008)更高效的更新查询(MS SQL Server 2008)
【发布时间】:2014-08-21 19:15:22
【问题描述】:

我正在尝试使用 TableB 中的相应 ADDR_ID 更新下面 TableA 中的多个列。这是一个 sn-p,实际上我在 TableA 中有 30 个位置,在 TableB 中有 30 个 EXT_ID,因此执行更新语句需要很长时间。问题是 TableA 中的 30 个位置中的任何一个都可能存在于 TableB 中的 30 个 EXT_ID 中的任何一个中。

例如,在 TableA 中,ID = 44231,位置 A35555 可能在 EXT_ID_27 中的 TableB 中匹配,所以我真的希望有人能提出比 900 条更新语句更好的替代方案...

下面的 SQL 小提琴

表A

+---------+-----------+-------------------------------------+----------------+-------------------------------------+
| ID      | LOC_1     | LOC_1_ADDR_ID                       | LOC_2          | LOC_2_ADDR_ID                       |
+---------+-----------+-------------------------------------|----------------+-------------------------------------|
| 44231   | A35555    | Trying to Populate Should Be Z76543 | B68754         | Trying to Populate should be Z45545 |
| 87563   | A36666    | Trying to Populate Should Be Z83465 | Q23548         | Trying to Populate should be Z89224 |
| 85387   | R14587    | Trying to Populate Should be Z66371 | A35555         | Trying to Populate should be Z93827 |
+---------+-----------+-------------------------------------+----------------+-------------------------------------|

TableB(每个 REC_ID 的 EXT_ID 是唯一的,但多个 REC_ID 可能具有相同的 EXT_ID)

+---------+-----------+-------------+-----------+-----------+
| REC_ID  | ADDR_ID_1 | EXT_ID_1    | ADDR_ID_2 | EXT_ID_2  | (28 more external ID columns)
+---------+-----------+-------------+-----------+-----------+
| 44231   | Z76543    | A35555      | Z45545    | B68754    |
| 87563   | Z83465    | A36666      | Z89224    | Q23548    |
| 85387   | Z93827    | A35555      | Z66371    | R14587    |
+---------+-----------+-------------+-----------|-----------+

http://sqlfiddle.com/#!3/02d5c/5/0

感谢您的任何建议!

【问题讨论】:

  • 如果我理解正确的话,你需要用表B中的相应值更新表A中的30列,并且每个连接应该发生在不同的列上(LOC_1 = EXT_ID_1更新LOC_1_ADDR_ID,LOC_2 = EXT_ID_2更新 LOC_2_ADR_ID 等)?
  • 排序,Loc_1 = EXT_ID_1 到 EXT_ID_30(可能是 30 个 EXT_ID 列中的任何一个中的匹配项),但在这 30 个 EXT_ID 中只存在一个匹配项。我正在阅读您的建议,谢谢。

标签: sql sql-server sql-server-2008 sql-update


【解决方案1】:

如果表 B 中的 30 列“对”实际上是具有相同含义的重复数据(位置键/地址对),那么设计应该只有 2 列具有更多数据。实际的表没有按照这个设计,但是你查询的数据可以。

SELECT EXT_ID_1 AS EXT_ID, ADDR_ID_1 AS ADDR_ID FROM TableB UNION ALL
SELECT EXT_ID_2 AS EXT_ID, ADDR_ID_2 AS ADDR_ID FROM TableB UNION ALL
SELECT EXT_ID_3 AS EXT_ID, ADDR_ID_3 AS ADDR_ID FROM TableB UNION ALL
...
SELECT EXT_ID_30 AS EXT_ID, ADDR_ID_30 AS ADDR_ID FROM TableB

这将为您提供两列数据,这样更容易编写查询。将其转储到临时表(或表变量)中,您可以继续使用 30 条 UPDATE 语句,这比 900 条要好。

或者,您可以在单个语句中尝试此操作:

WITH (
  SELECT EXT_ID_1 AS EXT_ID, ADDR_ID_1 AS ADDR_ID FROM TableB UNION ALL
  SELECT EXT_ID_2 AS EXT_ID, ADDR_ID_2 AS ADDR_ID FROM TableB UNION ALL
  SELECT EXT_ID_3 AS EXT_ID, ADDR_ID_3 AS ADDR_ID FROM TableB UNION ALL
  ...
  SELECT EXT_ID_30 AS EXT_ID, ADDR_ID_30 AS ADDR_ID FROM TableB
) AS SimplifiedTableB
UPDATE TableA
SET
  LOC_1_ADDR_ID = COALESCE(TableB1.ADDR_ID, LOC_1_ADDR_ID),
  LOC_2_ADDR_ID = COALESCE(TableB2.ADDR_ID, LOC_2_ADDR_ID),
  LOC_3_ADDR_ID = COALESCE(TableB3.ADDR_ID, LOC_3_ADDR_ID),
  ...
  LOC_30_ADDR_ID = COALESCE(TableB30.ADDR_ID, LOC_30_ADDR_ID)
FROM
  TableA
  LEFT JOIN SimplifiedTableB AS TableB1 ON TableA.LOC1 = TableB1.EXT_ID
  LEFT JOIN SimplifiedTableB AS TableB2 ON TableA.LOC2 = TableB2.EXT_ID
  LEFT JOIN SimplifiedTableB AS TableB3 ON TableA.LOC3 = TableB3.EXT_ID
  ...
  LEFT JOIN SimplifiedTableB AS TableB30 ON TableA.LOC30 = TableB30.EXT_ID

不过,出于正确性和性能方面的原因,我建议您事先对此进行测试。

【讨论】:

  • 这很好,我需要添加 REC_ID,因为 EXT_ID 在表中不是唯一的,但它适用于每个 REC_ID,因此这使我能够确定每个 REC_ID 是否存在 EXT_ID 并返回关联的 ADDR_ID . TableB 只有 90k 条记录并且增长缓慢,因此即使这会生成一个包含约 3M 条记录的表,它对于它所支持的日常工作也能正常工作。谢谢乔纳森!
【解决方案2】:

注意到这个问题已经得到解答,因为无论如何我都在研究这个问题,所以这里有一个替代方案.. 从Unpivot multi columns收到的一些信息

select tblB.REC_ID, tblB.ADDR_ID, tblB.EXT_ID
into #tempTableB
from
(
  select REC_ID, ADDR_ID, EXT_ID
  from TableB
  Unpivot
    (
      ADDR_ID for ADDR_IDS in (ADDR_ID_1, ADDR_ID_2)
    ) as UnPvtADDR
  Unpivot
    (
      EXT_ID for EXT_IDS in (EXT_ID_1, EXT_ID_2)

    ) as UnPvtEXT
  where RIGHT(ADDR_IDS, 1) = RIGHT(EXT_IDS, 1)
) tblB

-- [depend on number of records in #tmepTableB]
-- Create Index on #tempTablB.REC_ID to improve performance if required

update tblA
set LOC_1_ADDR_ID = (select ADDR_ID from #tempTableB where REC_ID = tblA.ID and EXT_ID = tblA.LOC_1)
, LOC_2_ADDR_ID = (select ADDR_ID from #tempTableB where REC_ID = tblA.ID and EXT_ID = tblA.LOC_2)
-- .. and the rest of the columns
from TableA tblA
  inner join
  #tempTableB tblB
on tblA.ID = tblB.REC_ID
where tblA.ID = tblB.REC_ID

select * from TableA

【讨论】:

    猜你喜欢
    • 2013-06-12
    • 1970-01-01
    • 1970-01-01
    • 2015-09-05
    • 1970-01-01
    • 2020-12-04
    • 1970-01-01
    • 2021-07-20
    • 2011-06-14
    相关资源
    最近更新 更多