我正面临一个复杂的SQL更新案例,我无法弄清楚如何解决。
我有nvarchar(32)
类型的列,其中包含" 952683174"等数字。我需要根据以下规则替换它的字符串:
所以前面的列值" 952683174"将是" 695834321"在表上执行更新查询后。
答案 0 :(得分:4)
编辑:这适用于SQL Server 2017及更高版本。
TRANSLATE
功能。
select TRANSLATE(yourcolumn,'123456789','354198236') FROM yourtable;
答案 1 :(得分:4)
您可以先用另一个字符替换每个数字,然后将字符替换为相应的数字,如下所示:
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')
答案 2 :(得分:3)
较新版本的SQL Server有更好的解决方案 - 例如2017版本中引入的Translate
内置函数。
但是,由于这是2008版本,您必须自己操纵字符串。
我建议的解决方案是使用表格进行翻译,与DhruvJoshi的答案(我认为我的答案更简单)不完全相同,但这是一种非常类似的方法。
话虽如此,这是另一种方法,根本不使用replace
:
首先,创建并填充样本表(请在将来的问题中保存此步骤):
DECLARE @T AS TABLE
(
Col nvarchar(32)
)
INSERT INTO @T (Col) VALUES
('952683174'),
('123456789'),
('06432') -- added more values to make sure I didn't mess it up
然后,创建并填充转换表:
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的The "Numbers" or "Tally" Table: What it is and how it replaces a loop),cross apply
并离开加入进行翻译,并for xml path
作为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
结果:
col translated
952683174 695834321
123456789 354198236
06432 08145 -- Note that the 0 doesn't get translated...
You can see a live demo on rextester.
与目前提供的其他答案相比,我的解决方案的主要优势:
答案 3 :(得分:0)
您可以使用如下查询: 的 See live demo 强> 解释是在评论中内联
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