【问题标题】:Update a SQL Server table from a CTE and Case statement从 CTE 和 Case 语句更新 SQL Server 表
【发布时间】:2017-10-30 19:11:30
【问题描述】:

我有这个代码:

WITH CTE AS
(
    SELECT 
        LTRIM(RTRIM([EMP_ID])) AS empID
    FROM 
        [SAMPLE].[dbo].[segments]
)
SELECT
    (CASE WHEN LEN(LTRIM(RTRIM(EMPID))) = 5 
             THEN RIGHT(('100' + EMPID), 8)
          WHEN LEN(LTRIM(RTRIM(EMPID))) = 6 
             THEN RIGHT(('10' + EMPID), 8)
          WHEN LEN(EMPID) = 7 
             THEN RIGHT('10' + (LEFT(LTRIM(EMPID), 6)), 8)
          ELSE empID
     END) EMP_ID
FROM CTE

我想要做的是使用上述状态将我的emp_id 列更新为新的 8 位 id。现在运行脚本会正确返回 ID,我只需要更新表格即可。

我尝试了以下方法,它所做的只是使所有 ID 都相同

WITH CTE AS 
(
    SELECT 
        LTRIM(RTRIM([EMP_ID])) AS empID
    FROM 
        [SAMPLE].[dbo].[segments]
)
UPDATE segments
SET EMP_ID = (case when len(ltrim(rtrim(EMPID))) = 5 then right(('100' + EMPID),8 )
        when len(ltrim(rtrim(EMPID))) = 6 then right(('10' + EMPID),8 )
        when len(EMPID) = 7 then right('10'+(left(ltrim(EMPID),6)),8)
      else empID
      end) 
FROM CTE

为此使用的正确UPDATE 语句是什么?

【问题讨论】:

  • 为什么不直接使用简单的更新呢?为什么是 CTE?
  • 是否有任何 EmpID 包含非数字字符?
  • 哦,当您已经检查了一个字符串的长度是 5 个字符并在前面添加 3 个字符时,您不需要再次将字符串修剪回 8 个字符。 6 和 2 相同。

标签: sql-server-2012 sql-server-2014 common-table-expression


【解决方案1】:

common table expression 中包含基列并直接更新cte

;with cte as (
  select 
      emp_id
    , empid = '1'+replicate('0',7-len(ltrim(rtrim([emp_id]))))+ltrim(rtrim(emp_id))
  from segments
  where len(ltrim(rtrim([emp_id]))) < 8
)

update cte set emp_id = empid;

select *
from segments;

rextester 演示:http://rextester.com/YKO33009

返回:

+----------+
|  emp_id  |
+----------+
| 88888888 |
| 17777777 |
| 10666666 |
| 10055555 |
| 10004444 |
| 10000333 |
| 10000022 |
| 10000001 |
+----------+

从此测试设置:

create table segments (emp_id char(8))
insert into segments values 
 ('88888888')
,('7777777')
,('666666')
,('55555')
,('4444')
,('333')
,('22')
,('1');

【讨论】:

  • 感谢 SqlZim 的解释和提示。这也很有效。非常感谢。
【解决方案2】:

如果修剪后的emp_id最左边的5或6个字符都是数字,你可以这样做:

UPDATE [SAMPLE].[dbo].[segments]
SET EMP_ID = cast(10000000 + cast(ltrim(rtrim( case when len(ltrim(rtrim(emp_id))) > 6 then left(ltrim(rtrim(emp_Id)),6) else ltrim(rtrim(emp_id)) end)) as int) as char(8))

如果您分两步进行,您可以更容易理解:

UPDATE [SAMPLE].[dbo].[segments]
SET Emp_ID = rtrim(ltrim(Emp_ID))

UPDATE [SAMPLE].[dbo].[segments]
SET EMP_ID = cast(10000000 + cast(case when len(emp_id) > 6 then left(emp_Id,6) else emp_id end as int) as char(8))

虽然我强烈怀疑这不是必需的,并且您的 EMP_ID 值已经被修剪。如果您知道 7 个字符的场景也是数字,它可能会变得更简单。

最后,我对没有WHEREUPDATE 查询感到非常紧张。有可能你这次真的是认真的……但跑起来还是很吓人。

【讨论】:

  • 感谢 Joel Coehoorn,非常感谢。
  • 是的,我明白你的意思,但这将是一次性交易 - 我们将所有 EMP_ID 从 5、6、7 位移动到 8 位。因此,我拥有的任何历史数据都需要转换为新的 8 位 ID。
【解决方案3】:

没有CTE你可以试试

UPDATE segments
SET EMP_ID = (case when len(ltrim(rtrim(EMP_ID))) = 5 then right(('100' + EMP_ID),8 )
    when len(ltrim(rtrim(EMP_ID))) = 6 then right(('10' + EMP_ID),8 )
    when len(EMP_ID) = 7 then right('10'+(left(ltrim(EMP_ID),6)),8)
  else emp_ID
  end)

或者如果你想使用 CTE,你可以尝试

With CTE
As 
(
SELECT ltrim(rtrim([EMP_ID])) as empIDTrim
, Emp_ID

FROM [SAMPLE].[dbo].[segments]
)
UPDATE CTE
SET EMP_ID = (case when len(empIDTrim)= 5 
then right('100' + empIDTrim,8 )
    when len(empIDTrim)= 6 
then right('10' + empIDTrim ,8 )
    when len(empIDTrim) = 7 
  then right('10'+left(empIDTrim,6),8)
  else empIDTrim
  end) 

【讨论】:

    猜你喜欢
    • 2012-05-18
    • 1970-01-01
    • 2016-07-08
    • 2015-02-27
    • 1970-01-01
    • 2011-08-27
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    相关资源
    最近更新 更多