缩短WHILE到单个UPDATE?

时间:2018-01-09 08:49:28

标签: sql sql-server

我在构建简洁的更新语句时遇到了麻烦。这是示例数据库的小提琴:http://sqlfiddle.com/#!6/6899b0

它包含具有多个地址的客户表。

现在我需要使用以下逻辑转换ABadrestype = '-1'中的[AdresBewoners]条目:

  • 仅转换ABtypebewoner = 'K'
  • 如果客户已有主要地址(ABadrestype = '1'),请将其更新为'2'
  • 否则,将第一个转换为'1',如果是多个,则将其他任何转换为​​'2'

这里是预期的结果(在示例db seed语句旁边注释,以清楚地看到需要更新的内容):

[dbo].[AdresBewoners] VALUES
    (1, 1, 1, 'K', '1'),
    (2, 2, 1, 'K', '2'),
    (3, 3, 2, 'K', '2'),
    (4, 4, 2, 'K', '-1'), -- change to 1, as it's the first for a customer without a principal address
    (5, 5, 2, 'K', '-1'), -- change to 2, as it's the second for a customer without a principal address
    (6, 6, 1, 'K', '-1'), -- change to 2, as the customer already has a principal address
    (7, 7, 3, 'Z', '1'),
    (8, 8, 3, 'Z', '-1')  -- leave as is; "Z" denotes other entity type

这可以在一个更新声明中完成吗?

编辑:这是等效的WHILE

-- Fetch affected records.
INSERT INTO
    #tmp_adresbewoners
SELECT
    ABid,
    ABidB
FROM
    AdresBewoners
WHERE
    ABtypebewoner = 'K'
    AND ABadrestype = '-1'

-- Declare cursor
DECLARE @cursor CURSOR
DECLARE @ABid int
DECLARE @ABidB int

SET @cursor = CURSOR FOR
    SELECT
        ABid,
        ABidB
    FROM
        #tmp_adresbewoners

OPEN @cursor
FETCH NEXT FROM @cursor INTO @ABid, @ABidB

WHILE @@FETCH_STATUS = 0
BEGIN

    UPDATE
        AdresBewoners
    SET
        -- If no principal address exists for the current customer, use '1', else use '2'
        ABadrestype = CASE
            WHEN NOT EXISTS (SELECT ABid FROM Adresbewoners WHERE ABidB = @ABidB AND ABtypebewoner = 'K' AND ABadrestype = '1') THEN '1'
            ELSE '2'
        END
    WHERE
        ABid = @ABid

    FETCH NEXT FROM @cursor INTO @ABid, @ABidB

END

CLOSE @cursor

问题仍然相同:可以在一个UPDATE语句中完成吗?

2 个答案:

答案 0 :(得分:1)

如果要插入所需的记录,请避免在表格上进行更新

INSERT INTO [dbo].[AdresBewoners] 
select [ABid], [ABidA], [ABidB], [ABtypebewoner],
       coalesce(case when (ABtypebewoner = 'K' and [ABadrestype] = -1) then null else [ABadrestype] end, 
               case when lag(ABadrestype) over (order by ABid) <> [ABadrestype] then 1 else 2 end) [ABadrestype]
from
(
    VALUES
    (1, 1, 1, 'K', '1'),
    (2, 2, 1, 'K', '2'),
    (3, 3, 2, 'K', '2'),
    (4, 4, 2, 'K', '-1'), -- change to 1, as it's the first for a customer without a principal address
    (5, 5, 2, 'K', '-1'), -- change to 2, as it's the second for a customer without a principal address
    (6, 6, 1, 'K', '-1'), -- change to 2, as the customer already has a principal address
    (7, 7, 3, 'Z', '1'),
    (8, 8, 3, 'Z', '-1')  -- lea
)a([ABid], [ABidA],[ABidB], [ABtypebewoner], [ABadrestype]) 

AND 如果您想强制更新命令而不是表,那可能就像

update a set a.ABadrestype = aa.[ABadrestype] from AdresBewoners a
join (
    select [ABid], [ABidA], [ABidB], [ABtypebewoner],  
       coalesce(case when (ABtypebewoner = 'K' and [ABadrestype] = -1) then null else [ABadrestype] end, 
               case when lag(ABadrestype) over (order by ABid) <> [ABadrestype] then 1 else 2 end) [ABadrestype]  from AdresBewoners
) aa on aa.ABid = a.ABid

答案 1 :(得分:0)

您可以通过以下查询进行更新。您可以将连接与其他表和更复杂的case子句一起使用。我不了解你的最后一个要求,所以你需要稍微升级一下。

update A
set A.ABadrestype = 
(CASE WHEN A.ABadrestype = 1 THEN 2 ELSE -1 END)
from Adresbewoners A
where A.ABtypebewoner = 'K'