Как перекодировать поле в эту конкретную структуру, используя T-SQL? - PullRequest
0 голосов
/ 25 сентября 2019

Я использую SQL Server 2014, и у меня есть столбец (ID) в таблице (tbl1).Идентификатор столбца представляет собой поле nvarchar.

Вот несколько примеров того, что он содержит:

   ID  
18FD64245
533040174
12AZ61356
19AK13355
18HD24189

Я хотел бы выполнить запрос T-SQL для перекодирования этих значений на основеследующая логика:

IF  THEN    IF  THEN
A   1       0   3
B   2       1   6
C   3       2   7
D   4       3   1
E   5       4   2
F   6       5   4
G   7       6   8
H   8       7   9
I   9       8   5
J   10      9   0
K   11          
L   12          
M   13          
N   14          
O   15          
P   16          
Q   17          
R   18          
S   19          
T   20          
U   21          
V   22          
W   23          
X   24          
Y   25          
Z   26  

Поэтому первые 2 значения, показанные выше, будут перекодированы как:

   ID         ID2
18FD64245  656482724
533040174  411323692

Мне трудно подойти к проблеме с точки T-SQLПосмотреть.Я думаю об использовании CASE операторов для решения проблемы.Я также взглянул на функцию REPLACE.Но я застрял в том, как это сделать, поскольку поле идентификатора является буквенно-цифровым полем.

Есть идеи, как мне двигаться дальше?

Редактировать (чтобы показать мой sqlкоды согласно ответу, предложенному @Squirrel):

declare @map table
(
    map_fr  char(1),
    map_to  varchar(2)
)


insert into @map 
values 

('A', '1'),
('B', '2'),
('C', '3'),
('D', '4'),
('E', '5'),
('F', '6'),
('G', '7'),
('H', '8'),
('I', '9'),
('J', '10'),
('K', '11'),
('L', '12'),
('M', '13'),
('N', '14'),
('O', '15'),
('P', '16'),
('Q', '17'),
('R', '18'),
('S', '19'),
('T', '20'),
('U', '21'),
('V', '22'),
('W', '23'),
('X', '24'),
('Y', '25'),
('Z', '26')


; with rcte as
(
    select  [ID], idx = 1, ch = substring([ID], 1, 1)
    from   Table1

    WHERE [ID] IS NOT NULL


    union all

    select  [ID], idx = idx + 1, ch = substring([ID], idx + 1, 1)
    from    rcte
    where   idx < len([ID])

),

cte as
(
    select  r.[ID], r.idx, m.map_to
    from    rcte r
            inner join @map m   on  r.ch = m.map_fr
)


select  [ID],
        (select '' + map_to from cte x where x.[ID] = c.[ID] order by idx for xml path('')) as ID2
from    cte c
group by [ID]
order by [ID]

Ответы [ 3 ]

2 голосов
/ 25 сентября 2019

Я бы создал таблицу сопоставления наподобие

declare @map table
(
    map_fr  char(1),
    map_to  varchar(2)
)

и вставил туда сопоставление

insert into @map 
values  ('A', '1'), ('B', '2'), ('C', '3'), ('D', '4'), ('E', '5'), ('F', '6'),
        ('G', '7'), ('H', '8'), ('I', '9'), ('J', '10'),('K', '11'),('L', '12'),
        ('M', '13'),('N', '14'),('O', '15'),('P', '16'),('Q', '17'),('R', '18'),
        ('S', '19'),('T', '20'),('U', '21'),('V', '22'),('W', '23'),('X', '24'),
        ('Y', '25'),('Z', '26'),
        ('0', '3'), ('1', '6'), ('2', '7'), ('3', '1'), ('4', '2'), ('5', '4'),
        ('6', '8'), ('7', '9'), ('8', '5'), ('9', '0')

, затем использовал бы рекурсивный CTE для разделения символа и соединения с таблицей сопоставления.И, наконец, объединить обратно строку, используя сопоставленное значение.

; with rcte as
(
    select  ID, idx = 1, ch = substring(ID, 1, 1)
    from    yourtbl 

    union all

    select  ID, idx = idx + 1, ch = substring(ID, idx + 1, 1)
    from    rcte
    where   idx < len(ID)

),
cte as
(
    select  r.ID, r.idx, m.map_to
    from    rcte r
            inner join @map m   on  r.ch    = m.map_fr
)
select  ID,
        (select '' + map_to from cte x where x.ID = c.ID order by idx for xml path('')) as ID2
from    cte c
group by ID
order by ID
0 голосов
/ 25 сентября 2019

Вы также можете отобразить их, используя таблицу подсчета и некоторые новые функции SQL Server 2017 (STRING_AGG):

SQL Fiddle

Настройка схемы MS SQL Server 2017 :

CREATE TABLE IDS
(
  ID NVARCHAR(9)
 )
 INSERT INTO IDS
 VALUES ('18FD64245'),
        ('533040174'),
        ('12AZ61356'),
        ('19AK13355'),
        ('18HD24189');

Запрос 1 :

WITH Tally
AS
(
  SELECT ROW_NUMBER() OVER (ORDER BY Nums.Num) AS Number
  FROM (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) AS Nums(Num)
  CROSS APPLY (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) AS Nums2(Num)
 ),
 Chars
 As
 (
   -- Turn each character of ID to new row
    SELECT ID, SUBSTRING(ID, Number, 1) AS OldChar, Number As Ind
    FROM IDS
    CROSS APPLY Tally
    WHERE SUBSTRING(ID, Number, 1) <> ''

  ),
  NewChars
  AS
  (
    -- Map old characters to new characters
    SELECT *, 
          CASE WHEN ISNumeric(OldChar) = 1 THEN
            -- effectively a mapping string to map old characters to new
            SUBSTRING('3671248950', CHARINDEX(OldChar, '0123456789'), 1)
           ELSE
             -- for alphanumeric we can simply make 'A' be 1 and 'B' be 2
             -- by subtracting the ASCII value of 'A' from the ASCII of the
             -- Character and add 1
              ASCII(OldChar) - ASCII('A') + 1
         END As NewChar
    FROM Chars
  )
  -- Recombine New Characters to form new Id (SQL Server 2017 only)
  SELECT ID, STRING_AGG(NewChar,'') WITHIN GROUP (ORDER BY Ind) AS NewId
  FROM NewChars
  GROUP BY ID
  ORDER BY Id

Результаты :

|        ID |      NewId |
|-----------|------------|
| 12AZ61356 | 6712686148 |
| 18FD64245 |  656482724 |
| 18HD24189 |  658472650 |
| 19AK13355 | 6011161144 |
| 533040174 |  411323692 |
0 голосов
/ 25 сентября 2019

Это лучше подходит как скалярная функция, но если вы хотите сделать все это с помощью одного оператора SQL, вот способ:

select ID,
       case substring(ID, 1, 1) when 'A' then '1'
                                when 'B' then '2'
                                ...
                                when '9' then '0'
       end
       +  
       case substring(ID, 2, 1) when 'A' then '1'
                                when 'B' then '2'
                                ...
                                when '9' then '0'
       end
       +
       ...
       ...
       case substring(ID, 9, 1) when 'A' then '1'
                                when 'B' then '2'
                                ...
                                when '9' then '0'
       end
       as ID2
from MY_TABLE
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...