SQL для разделения строки на дефис и последующего генерирования всех суффиксов для каждого чанка длиной 3 или более символов? - PullRequest
0 голосов
/ 18 апреля 2020

Я работаю с поисковой системой префиксов и пытаюсь сгенерировать суффиксные ключевые слова для своих номеров деталей.

** Пример строки: 123456-7890-A-BCDEF-GHIJ-KL

Я хочу разделить эта строка в чанки, например:

  123456
  7890
  A
  BCDEF
  GHIJ
  KL

Затем мне нужно сгенерировать суффиксы каждого чанка длиной более 3 символов в один список с разделителями-запятыми.

- Для фрагмента 123456 я получу суффиксы 23456, 3456, 456, 56

- Для фрагмента 7890 я получу суффиксы 890, 90

- Для фрагмента A , он будет проигнорирован, так как длина меньше 3 символов

- Для фрагмента BCDEF я получу суффиксы CDEF, DEF, EF

- Для фрагмента GHIJ получить суффиксы HIJ, IJ

- Для фрагмента KL он будет проигнорирован, так как его длина меньше 3 символов

В моей строке может быть любое количество символов в каждом чанк, они не всегда отформатированы, как в примере.

Таким образом, конечный результат для строки 123456-7890-A-BCDEF-GHIJ будет выглядеть так: s;

23456, 3456, 456, 56, 890, 90, CDEF, DEF, EF, HIJ, IJ

В моей строке может быть любое количество символов в каждом чанке, они не всегда форматируются, как в примере. Некоторые другие примеры строк;

123-4567890-ABC-DEFGHIJ-K-L

--Result: 23, 567890, 67890, 7890, 890, 90, BC, EFGHIJ, FGHIJ, GHIJ, HIJ, IJ

123456-7-890AB-CDEFG-H-IJKL

--Result: 23456, 3456, 456, 56, 90AB, 0AB, AB, DEFG, EFG, FG, JKL, KL

Ответы [ 3 ]

1 голос
/ 18 апреля 2020

Я признаю, что это не совсем то, что вы ищете, но это близко. Возможно, это даст вам или кому-то еще идею получить именно то, что вы хотите. Предполагается, что SQL Server 2017 или выше.

Поэтому я использую STRING_SPLIT () , чтобы разделить строку на одну строку для каждого куска, нумерация этих строк с использованием ROW_NUMBER () . С этим связана проблема, заключающаяся в том, что STRING_SPLIT () не гарантирует порядок.

Затем я использую CTE, чтобы в основном найти значения индекса для перехода между каждым фрагментом от 2 до длины фрагмента - 1 помещая эти строки обратно в список через запятую для каждого чанка с помощью STRING_AGG () .

Я вставляю эти результаты во временную таблицу, чтобы можно было выбирать их по порядку по номеру строки и собирать суффиксы из каждого куска в окончательный список, разделенный запятыми.

DECLARE @MyString VARCHAR(50);
SET @MyString = '123456-7890-A-BCDEF-GHIJ';

WITH   cte
AS     (SELECT 
          2 AS n -- anchor member
        , value 
        , ROW_NUMBER() OVER (ORDER BY value) AS [rn]
        FROM STRING_SPLIT(@MyString, '-')
        WHERE LEN(value) >= 3
        UNION ALL
        SELECT 
          n + 1
          , cte.value -- recursive member
          , cte.rn
        FROM   cte
        WHERE  n < (LEN(value) - 1) -- terminator
       )
SELECT STRING_AGG(SUBSTRING(value, n, LEN(value) - n + 1), ', ') as [Chunk]
INTO #Temp
FROM   cte
GROUP BY rn
ORDER BY rn;

SELECT STRING_AGG(Chunk, ', ')
FROM #Temp

Вот это dbfiddle .

0 голосов
/ 18 апреля 2020

- не производительно ... может быть, достаточно хорошо (?)

declare @t table
(
id int identity primary key clustered,
thecol varchar(40)
);

insert into @t(thecol)
values('1-2-3-4-5-6'), ('abcd') /*??*/;

insert into @t(thecol)
select top (10000) newid()
from master.dbo.spt_values as a
cross join master.dbo.spt_values as b;

select *,
thelist= replace(
cast('<!--'+replace(thecol, '-', '--><!--')+'-->' as xml).query('
let $seq := (2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20) (: note: max 22 chars per string-part:)
for $a in comment()
  let $str := string($a), $maxlen := string-length($str)-1
  for $i in $seq[. <= $maxlen]
    return concat(substring($str, $i, 100), "," )
').value('.', 'varchar(max)')+'_', ',_', '')
from @t;
0 голосов
/ 18 апреля 2020

Вероятно, есть более элегантный способ сделать это и, вероятно, лучшие строковые манипуляторы, чем t- sql, но, похоже, это работает: (требуется, чтобы DB был в режиме совместимости = SQL 2016 или выше, чтобы использовать STRING_SPLIT)

DECLARE @STRING     VARCHAR (100)
DECLARE @DIVIDEON   CHAR (1)
DECLARE @FULLSTRING VARCHAR (100)
DECLARE @SUBSTR     VARCHAR (100) 
DECLARE @WRKSTRING  VARCHAR (100)
DECLARE @LEN        TINYINT

SELECT  @STRING = '123456-7-890AB-CDEFG-H-IJKL'
SELECT  @DIVIDEON = '-'
SELECT  @FULLSTRING =''

IF OBJECT_ID('tempdb..#mytable') IS NOT NULL
DROP TABLE #mytable     

select RIGHT(value,LEN(value)-1) as MyString 
into #mytable
from STRING_SPLIT (@STRING, @DIVIDEON)  -- only SQL 2016 and above
where len(value)>2 -- ignore subsets that do not have 3 or more chars

while exists (select MyString from #mytable)
begin
   select @WRKSTRING = (select top 1 MyString from #mytable)
   select @LEN = len(@WRKSTRING)
   select @SUBSTR=@WRKSTRING
   while @LEN>2
   begin
      select @SUBSTR=@SUBSTR+', '+RIGHT(@WRKSTRING,@LEN-1)
      select @LEN=@LEN-1
   end
   delete from #mytable where MyString = @WRKSTRING
   --select @SUBSTR as Fullstr
   select @FULLSTRING=@FULLSTRING+@SUBSTR+','

end
   select LEFT(@FULLSTRING,LEN(@FULLSTRING)-1)
drop table #mytable
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...