Sql 根据模式更新和替换字符串值
我面临着一个复杂的sql更新案例,我不知道如何解决它 我有一个类型为Sql 根据模式更新和替换字符串值,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我面临着一个复杂的sql更新案例,我不知道如何解决它 我有一个类型为nvarchar(32)的列,它由像“952683174”这样的数字组成。我确实需要根据以下规则替换其字符串: 1替换为3 2替换为5 3替换为4 4替换为1 5替换为9 6替换为8 7替换为2 8替换为3 9替换为6 因此,在对表执行更新查询后,上一列值“952683174”将为“695834321”。编辑:这适用于SQL Server 2017及更高版本 翻译功能 select TRANSLATE(yourcolumn,
nvarchar(32)
的列,它由像“952683174”这样的数字组成。我确实需要根据以下规则替换其字符串:
- 1替换为3
- 2替换为5
- 3替换为4
- 4替换为1
- 5替换为9
- 6替换为8
- 7替换为2
- 8替换为3
- 9替换为6
因此,在对表执行更新查询后,上一列值“952683174”将为“695834321”。编辑:这适用于SQL Server 2017及更高版本
翻译
功能
select TRANSLATE(yourcolumn,'123456789','354198236') FROM yourtable;
您可以先用另一个字符替换每个数字,然后用相应的数字替换该字符,如下所示:
DECLARE @number nvarchar(32) = '952683174';
SELECT
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
@number,
'1', 'A'),'2', 'B'),'3', 'C'),'4', 'D'),'5', 'E'),'6', 'F'),'7', 'G'),'8', 'H'),'9', 'I'),
'A', '3'),'B', '5'),'C', '4'),'D', '1'),'E', '9'),'F', '8'),'G', '2'),'H', '3'),'I', '6')
您可以使用如下查询: 解释内嵌在注释中
create table numbers (n nvarchar(32));
insert into numbers values ('952683174'),('5785348');
-- 1. We create ordering on numbers to retain original order
; with ordered_numbers
as
(
select
n,
r= row_number() over(order by (SELECT NULL))
from numbers
),
-- 2. we create a tally table to split out each digit position wise and replace with mapping in V(old,new)
cte as
(
select
newdigit= v.new,r
from
ordered_numbers
cross apply
(
select
top (select LEN(n))
row_number() over (order by (select null)) rn
from
sys.objects o1 cross join sys.objects o2)tally
join
(
values
('1','3'),
('2','5'),
('3','4'),
('4','1'),
('5','9'),
('6','8'),
('7','2'),
('8','3'),
('9','6')
)v(old,new)
on v.old=SUBSTRING(n,rn,1)
)
--3. We join back the digits into a single string using order created in step 1
SELECT n = REPLACE((
select '|' + newdigit
from cte c1
where c1.r=c2.r
FOR XML PATH('')
),'|','')
FROM cte c2
group by c2.r
order by c2.r asc
较新版本的SQL Server对此有更好的解决方案,例如2017年版本中引入的
Translate
内置功能
但是,由于这是2008版本,您必须自己操作字符串
我建议的解决方案是使用一个表进行翻译,与DhruvJoshi的答案不太一样(我认为我的答案更简单),但方法非常相似
话虽如此,这里有另一种方法,根本不使用replace
:
首先,创建并填充示例表(请在以后的问题中保存此步骤):
然后,创建并填充翻译表:
DECLARE @Translate AS TABLE
(
original char(1),
translation char(1)
)
INSERT INTO @Translate (original, translation) VALUES
('1', '3'),
('2', '5'),
('3', '4'),
('4', '1'),
('5', '9'),
('6', '8'),
('7', '2'),
('8', '3'),
('9', '6')
现在,使用堆叠的cte作为理货表替换(如果有,当然可以使用实际的理货表。如果没有,请阅读Jeff Moden的),交叉应用
和左连接来进行转换,对于xml路径
作为string_agg(另一个在2017年版本中最终构建的函数),您可以这样做:
;WITH E1(N) AS (SELECT 1 FROM (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) V(v)), --10E+1 or 10 rows
E2(N) AS (SELECT 1 FROM E1 a CROSS JOIN E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a CROSS JOIN E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4)
SELECT Col,
(
SELECT ISNULL(translation, c)
FROM @T as t1
CROSS APPLY
(
SELECT Substring(Col, N, 1) As c, translation
FROM cteTally
LEFT JOIN @Translate ON Substring(Col, N, 1) = original
WHERE N <= LEN(ISNULL(Col, ''))
) as t2
WHERE t1.Col = t0.Col
FOR XML PATH('')
) As translated
FROM @T t0
与目前提供的其他答案相比,我的解决方案的主要优点:
否。2017年引入翻译。问题是关于2008年版的。@ZoharPeled:对不起。。我不知道。。我可能会用一个免责声明来保留这个答案,这在将来可能会有所帮助!。这也是我最初的方法,+1.@Mats现在感谢您的帮助,但我如何将其与update语句结合起来呢。i、 e.要遍历所有列值并根据此规则进行更新?@Dana您可以在update语句中将
@number
替换为columnname。例如:updateyourtable SET yourColumn=REPLACE(REPLACE…,yourColumn,'1','A','2','B')…
;WITH E1(N) AS (SELECT 1 FROM (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) V(v)), --10E+1 or 10 rows
E2(N) AS (SELECT 1 FROM E1 a CROSS JOIN E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a CROSS JOIN E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4)
SELECT Col,
(
SELECT ISNULL(translation, c)
FROM @T as t1
CROSS APPLY
(
SELECT Substring(Col, N, 1) As c, translation
FROM cteTally
LEFT JOIN @Translate ON Substring(Col, N, 1) = original
WHERE N <= LEN(ISNULL(Col, ''))
) as t2
WHERE t1.Col = t0.Col
FOR XML PATH('')
) As translated
FROM @T t0
col translated
952683174 695834321
123456789 354198236
06432 08145 -- Note that the 0 doesn't get translated...