您可以使用Recursive CTE以递归应用REPLACE
功能:
;WITH StripSpecialChars AS (
SELECT id, 0 AS lvl,
[EpiNum] = REPLACE([EpiNum], SUBSTRING([EpiNum], x.i, 1), ''),
[Name] = REPLACE([Name], SUBSTRING([Name], y.i, 1), ''),
[Acct] = REPLACE([Acct], SUBSTRING([Acct], z.i, 1), '')
FROM TableA
CROSS APPLY (SELECT PATINDEX('%[^a-zA-Z0-9 ]%', [EpiNum])) AS x(i)
CROSS APPLY (SELECT PATINDEX('%[^a-zA-Z0-9 ]%', [Name])) AS y(i)
CROSS APPLY (SELECT PATINDEX('%[^a-zA-Z0-9 ]%', [Acct])) AS z(i)
WHERE x.i <> 0 OR y.i <> 0 OR z.i <> 0
UNION ALL
SELECT id, lvl = lvl + 1,
[EpiNum] = REPLACE([EpiNum], SUBSTRING([EpiNum], x.i, 1), ''),
[Name] = REPLACE([Name], SUBSTRING([Name], y.i, 1), ''),
[Acct] = REPLACE([Acct], SUBSTRING([Acct], z.i, 1), '')
FROM StripSpecialChars
CROSS APPLY (SELECT PATINDEX('%[^a-zA-Z0-9 ]%', [EpiNum])) AS x(i)
CROSS APPLY (SELECT PATINDEX('%[^a-zA-Z0-9 ]%', [Name])) AS y(i)
CROSS APPLY (SELECT PATINDEX('%[^a-zA-Z0-9 ]%', [Acct])) AS z(i)
WHERE x.i <> 0 OR y.i <> 0 OR z.i <> 0
)
的CTE终止,只要没有多个特殊字符来代替。
具有每id
最大lvl
值的行是包含[EpiNum]
,[Name]
,[Acct]
字段的剥离下来值之一。因此,你可以使用下面的代码在一个单独的SQL语句执行UPDATE
:
;WITH StripSpecialChars AS (
... above query here ...
)
UPDATE t1
SET t1.[EpiNum] = t2.[EpiNum],
t1.[Name] = t2.[Name],
t1.[Acct] = t2.[Acct]
FROM TableA AS t1
INNER JOIN (SELECT id, [EpiNum], [Name], [Acct],
ROW_NUMBER() OVER (PARTITION BY id
ORDER BY lvl DESC) AS rn
From StripSpecialChars) AS t2
ON t1.id = t2.id AND t2.rn = 1
Demo here
编辑:
但如果是在TableA
没有PK列,那么你就可以用CTE
包装你的表格,使用ROW_NUMBER
模拟PK,最后在CTE
上执行更新:
;WITH TableA_PK AS (
SELECT [EpiNum], [Name], [Acct],
ROW_NUMBER() OVER (ORDER BY [EpiNum]) AS id
FROM TableA
), StripSpecialChars AS (
SELECT id, 0 AS lvl,
[EpiNum] = REPLACE([EpiNum], SUBSTRING([EpiNum], x.i, 1), ''),
[Name] = REPLACE([Name], SUBSTRING([Name], y.i, 1), ''),
[Acct] = REPLACE([Acct], SUBSTRING([Acct], z.i, 1), '')
FROM TableA_PK
CROSS APPLY (SELECT PATINDEX('%[^a-zA-Z0-9 ]%', [EpiNum])) AS x(i)
CROSS APPLY (SELECT PATINDEX('%[^a-zA-Z0-9 ]%', [Name])) AS y(i)
CROSS APPLY (SELECT PATINDEX('%[^a-zA-Z0-9 ]%', [Acct])) AS z(i)
WHERE x.i <> 0 OR y.i <> 0 OR z.i <> 0
UNION ALL
SELECT id, lvl = lvl + 1,
[EpiNum] = REPLACE([EpiNum], SUBSTRING([EpiNum], x.i, 1), ''),
[Name] = REPLACE([Name], SUBSTRING([Name], y.i, 1), ''),
[Acct] = REPLACE([Acct], SUBSTRING([Acct], z.i, 1), '')
FROM StripSpecialChars
CROSS APPLY (SELECT PATINDEX('%[^a-zA-Z0-9 ]%', [EpiNum])) AS x(i)
CROSS APPLY (SELECT PATINDEX('%[^a-zA-Z0-9 ]%', [Name])) AS y(i)
CROSS APPLY (SELECT PATINDEX('%[^a-zA-Z0-9 ]%', [Acct])) AS z(i)
WHERE x.i <> 0 OR y.i <> 0 OR z.i <> 0
)
UPDATE t1
SET t1.[EpiNum] = t2.[EpiNum],
t1.[Name] = t2.[Name],
t1.[Acct] = t2.[Acct]
FROM TableA_PK AS t1
INNER JOIN (SELECT id, [EpiNum], [Name], [Acct],
ROW_NUMBER() OVER (PARTITION BY id
ORDER BY lvl DESC) AS rn
FROM StripSpecialChars) AS t2
ON t1.id = t2.id AND t2.rn = 1
Demo here
非常感谢您的答复/时间。我认为这是我的赢家,因为它不需要函数调用,看起来会很快。有一个问题,我不想通过添加'id'列来修改我的初始表结构。我不清楚这是否可以使用上述方法完成?任何想法非常感谢... – MoonKnight
@Killercam请检查我所做的编辑。 –
这真是太好了,非常感谢你的时间...... – MoonKnight