Обновить и заменить строковые значения в соответствии с шаблоном - PullRequest
0 голосов
/ 01 мая 2018

У меня сложный случай обновления SQL, который я не могу понять, как решить.

У меня есть столбец типа nvarchar(32), который состоит из чисел типа "952683174". Мне нужно заменить его строку в соответствии со следующими правилами:

  • 1 заменить на 3
  • 2 заменить на 5
  • 3 заменить на 4
  • 4 заменить на 1
  • 5 заменить на 9
  • 6 заменить на 8
  • 7 заменить на 2
  • 8 заменить на 3
  • 9 заменить на 6

Таким образом, предыдущее значение столбца «952683174» будет «695834321» после выполнения запроса на обновление таблицы.

Ответы [ 4 ]

0 голосов
/ 01 мая 2018

Более новые версии SQL Server имеют лучшие решения для этого, такие как встроенная функция Translate, представленная в версии 2017 года.

Однако, поскольку это версия 2008 года, вам придется самостоятельно манипулировать строкой.

Мое предлагаемое решение состоит в том, чтобы использовать таблицу для переводов, не совсем такую ​​же, как ответ ДхрувДжоши (я думаю, что мой проще), но очень похожий подход.

Сказав это, вот еще один подход, который вообще не использует 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 в качестве замены таблицы подсчета (конечно, вы можете использовать фактическую таблицу подсчета, если она у вас есть. Если нет, прочитайте таблицу «Числа» или «Подсчет» Джеффа Модена: Что и как он заменяет цикл ), 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...

Вы можете увидеть живое демо на rextester.

Основные преимущества моего решения по сравнению с другим ответом, предоставленным в настоящее время:

  1. Подход, основанный на всех наборах, без использования замены или манипуляции со строками.
  2. Все переводы хранятся в виде табличных значений. Ничто не жестко закодировано.
  3. Значения перевода не ограничены одним символом. Если вы решите перевести 9 на 11, вам потребуется только изменить таблицу перевода (ответ MatSnow также имеет это преимущество)
0 голосов
/ 01 мая 2018

Вы можете сначала заменить каждое число другим символом, а затем заменить символ на соответствующее число следующим образом:

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')

Демо

0 голосов
/ 01 мая 2018

Вы можете использовать запрос, как показано ниже: См. Демо-версию Объяснение встроено в комментарии

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
0 голосов
/ 01 мая 2018

РЕДАКТИРОВАТЬ : Это работает для SQL Server 2017 и выше.

TRANSLATE функция.

select TRANSLATE(yourcolumn,'123456789','354198236') FROM yourtable;

Демо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...