Обратный порядок каждого другого символа в строке - PullRequest
1 голос
/ 02 октября 2019

В настоящее время я работаю над проектом, в котором данные, которые я получаю, передаются мне в беспорядочном порядке. Мне нужно каждые 2 символа для переключения мест в строке. В настоящее время у меня есть код ниже, но он неоправданно медленный в функции или хранимой процедуре. Любая помощь будет оценена.

Пример: FK741 OCEV должно быть KF47 1COVE

ALTER FUNCTION [dbo].[UnscrambleData] 
(
    @scrambled varchar(50) 
)
RETURNS varchar(50)
AS
BEGIN
    Declare @unscrambled varchar(50)
    Declare @temp1 varchar(1)
    DECLARE @cnt INT = 0;
    Declare @cnt_Total INT =len(@scrambled)

    WHILE @cnt < = @cnt_total
       if((@cnt%2)=0)
       begin 
             set @unscrambled=CONCAT( @unscrambled,SUBSTRING(@scrambled, @cnt, 1),@temp1)
             set @temp1=''
       end
   else if (@cnt_Total%2<>0 and @cnt_Total-@cnt<2)
       begin
              set @unscrambled=CONCAT( @unscrambled,SUBSTRING(@scrambled, @cnt, 1))
       end
   else
       begin
             set @temp1= SUBSTRING(@scrambled, @cnt, 1)
       end
   SET @cnt = @cnt + 1;

    RETURN @unscrambled;
END

Ответы [ 3 ]

4 голосов
/ 02 октября 2019

Вы можете сделать это как

SELECT STRING_AGG(REVERSE(V), '')
FROM
(
  VALUES
  ('FK741 OCEV')
) T(Str) CROSS APPLY
(
  SELECT SUBSTRING(Str, Number-1, 2)
  FROM Master..spt_values --Tally table
  WHERE [Type] = 'P'
        AND Number BETWEEN 1 AND LEN(Str)
        AND Number % 2 = 0
) TT(V)

Возвраты:

KF47 1COVE

Демонстрация в Интернете

Если у вас более одной строки, то

SELECT STRING_AGG(REVERSE(V), '')
FROM
(
  VALUES
  (1, 'FK741 OCEV'),
  (2, 'ABC DEF GH'),
  (3, 'THIRD STRING')
) T(Id, Str) CROSS APPLY
(
  SELECT SUBSTRING(Str, Number-1, 2)
  FROM Master..spt_values
  WHERE [Type] = 'P'
        AND Number BETWEEN 1 AND LEN(Str)
        AND Number % 2 = 0
) TT(V)
GROUP BY T.Id;
3 голосов
/ 02 октября 2019

Если вам не нужно решение на основе множеств, вы можете использовать цикл, который работает быстрее, чем ваше текущее решение (по крайней мере, на основе моего теста):

DECLARE @scrambled VARCHAR(50) = 'FK741 OCEV';
DECLARE @test_unscrambled VARCHAR(50) = 'KF47 1COVE';
DECLARE @unscrambled VARCHAR(50) = '';

DECLARE @idx INT = 1;
DECLARE @this_char CHAR(1), @next_char CHAR(1);

WHILE @idx <= LEN(@scrambled)
BEGIN
    SET @this_char = SUBSTRING(@scrambled, @idx, 1);
    SET @next_char = SUBSTRING(@scrambled, @idx + 1, 1);
    SET @unscrambled = @unscrambled + @next_char + @this_char;

    SET @idx = @idx + 2;
END
1 голос
/ 02 октября 2019

@ sami опубликовал единственное высокопроизводительное решение на основе множеств;это тот, чтобы пойти с.

Однако вы можете обмануть и использовать [ngrams8K]. Это будет очень быстро и с упрощенным кодом. 1 .

DECLARE @string VARCHAR(100) = 'FK741 OCEV';

SELECT NewString = 
(
  SELECT   REVERSE(ng.token) 
  FROM     dbo.ngrams8k(@string,2) AS ng
  WHERE    ng.position%2=1
  ORDER BY ng.position
  FOR XML PATH('')
); 

Возвраты: KF47 1COVE

Против таблицы:

WITH SampleData AS 
  (SELECT TOP (10) OldString=STUFF(LEFT(NEWID(),7),5,0,' ') FROM sys.all_columns)
SELECT s.OldString, f.NewString
FROM   SampleData AS s
CROSS APPLY
(
  SELECT   REVERSE(ng.token) 
  FROM     dbo.ngrams8k(s.OldString,2) AS ng
  WHERE    ng.position%2=1
  ORDER BY ng.position
  FOR XML PATH('')
) AS f(NewString);

Возвраты:

OldString  NewString
---------- ----------
D82E EDE   8DE2E ED
655C E83   56C5E 38
307D 62B   03D76 B2
F485 83A   4F588 A3
80DF ABB   08FDA BB
EC97 EB3   CE79E 3B
7279 DE6   2797D 6E
06A8 35B   608A3 B5
8CBD D1E   C8DBD E1
D17B 3A0   1DB73 0A
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...