Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 根据模式更新和替换字符串值_Sql_Sql Server_Sql Server 2008 - Fatal编程技术网

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,

我面临着一个复杂的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,'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

与目前提供的其他答案相比,我的解决方案的主要优点:

  • 所有基于集合的方法,不使用替换或字符串操作
  • 所有翻译都存储为表值。没有什么是硬编码的
  • 翻译值不限于一个字符。如果您决定将9转换为11,则只需更改转换表(MatSnow的答案也有此好处)

  • 否。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...