更高效的更新查询(MS SQL Server 2008)

时间:2014-08-21 19:15:22

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

我尝试使用TableB中相应的ADDR_ID更新下面TableA中的多个列。这是一个片段,实际上我在TableA中有30个位置,在TableB中有30个EXT_ID,因此执行Update语句会花费一些时间。问题是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 |
+---------+-----------+-------------------------------------+----------------+-------------------------------------|

表B(EXT_ID对于每个REC_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

感谢您的任何建议!

2 个答案:

答案 0 :(得分: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

但是,出于正确性和性能原因,我建议事先对此进行测试。

答案 1 :(得分:1)

注意到这已得到解答,因为无论如何我正在研究这个问题,这里有一个替代方案.. 从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