T-SQL удаляет несколько символов из строки после разделителей - PullRequest
0 голосов
/ 04 ноября 2019

Строка, которая передается хранимой процедуре как переменная, выглядит следующим образом:

'10273955=1|10142823=5|10664263=10|10134335=3|10046639=3|10334724=25|10334725=100'

Я ищу быстрый способ ее анализа:

'10273955|10142823|10664263|10134335|10046639|10334724|10334725'

SQL-сервер 2016

Ответы [ 3 ]

3 голосов
/ 04 ноября 2019

Мое предложение было следующим:

A таблица макетов для имитации вашей проблемы

DECLARE @tbl TABLE(ID INT IDENTITY, YourString VARCHAR(250));
INSERT INTO @tbl VALUES('10273955=1|10142823=5|10664263=10|10134335=3|10046639=3|10334724=25|10334725=100');

- Запрос

SELECT t.ID
      ,t.YourString
      ,A.CastedToXml
      ,REPLACE(A.CastedToXml.query('data(/x/y[1])').value('.','varchar(150)'),' ','|')
FROM @tbl t
CROSS APPLY(SELECT CAST('<x><y>' + REPLACE(REPLACE(t.YourString,'|','</y></x><x><y>'),'=','</y><y>') + '</y></x>' AS XML)) A(CastedToXml);

результат

10273955|10142823|10664263|10134335|10046639|10334724|10334725

Идея вкратце:

APPLY будет использовать некоторые замены для преобразования двойного XML-кода за один раз. Это будет выглядеть так:

<x>
  <y>10273955</y>
  <y>1</y>
</x>
<x>
  <y>10142823</y>
  <y>5</y>
</x>
<x>
  <y>10664263</y>
  <y>10</y>
</x>
<x>
  <y>10134335</y>
  <y>3</y>
</x>
<x>
  <y>10046639</y>
  <y>3</y>
</x>
<x>
  <y>10334724</y>
  <y>25</y>
</x>
<x>
  <y>10334725</y>
  <y>100</y>
</x>

Хитрость заключается в использовании data() XQuery, который возвращает все значения в XPath в виде пробел отдельных фрагментов. Использование XPath /x/y[1] говорит движку: Выберите каждый <x> и первый <y>, который вы там найдете! .

Кстати: в XMLпорядок сортировки исправлен. Таким образом, возвращаемая строка не изменит этот порядок.

0 голосов
/ 04 ноября 2019

Используя Ngrams8k, вы можете сделать это:

DECLARE @string VARCHAR(1000) = 
  '10273955=1|10142823=5|10664263=10|10134335=3|10046639=3|10334724=25|10334725=100';

SELECT NewString = 
(
  SELECT CASE SIGN(s.position) WHEN 1 THEN '' ELSE ng.token END
  FROM   dbo.NGrams8k(@string,1) AS ng
  LEFT JOIN 
  (
    SELECT ng.position, nxt.Pos, ln=nxt.Pos-ng.position
    FROM   dbo.ngrams8k(@string,1) AS ng
    CROSS APPLY (VALUES(
      ISNULL(NULLIF(CHARINDEX('|',@string, ng.position+1),0),LEN(@string)+1))) AS nxt(Pos)
    WHERE  ng.token = '='
  ) AS s ON ng.position BETWEEN s.position AND s.pos-1
  ORDER BY ng.position ASC
  FOR XML PATH('')
);

Возвращает:

NewString
---------------------------------------------------------------------------------
10273955|10142823|10664263|10134335|10046639|10334724|10334725
0 голосов
/ 04 ноября 2019

Используя DelimitedSplit8K_LEAD и FOR XML PATH (поскольку в 2017 году вводится STRING_AGG), вы можете сделать это и сохранить порядок, но реальное решение - прекратить хранение данных с разделителями (да, я сделалхочу сказать, разделить дважды, как | и = разделено) в ваших таблицах ...

SELECT YT.YourColumn,
       STUFF((SELECT '|' + LEFT(DS.Item,CHARINDEX('=',DS.item)-1)
              FROM dbo.DelimitedSplit8K_LEAD(YT.YourColumn,'|') DS
              ORDER BY DS.ItemNumber
              FOR XML PATH(''),TYPE).value('.','varchar(8000)'),1,1,'') AS NewColumn        
FROM (VALUES('10273955=1|10142823=5|10664263=10|10134335=3|10046639=3|10334724=25|10334725=100'))YT(YourColumn)

Но, как я уже сказал, исправьте свой дизайн. Вы можете сделать это снова с помощью DelimitedSplit8K_LEAD:

SELECT DS1.ItemNumber AS ID,
       CONVERT(int,MAX(CASE DS2.ItemNumber WHEN 1 THEN DS2.Item END)) AS LongNumber,
       CONVERT(int,MAX(CASE DS2.ItemNumber WHEN 2 THEN DS2.Item END)) AS ShortNumber
FROM (VALUES('10273955=1|10142823=5|10664263=10|10134335=3|10046639=3|10334724=25|10334725=100'))YT(YourColumn)
     CROSS APPLY dbo.DelimitedSplit8K_LEAD(YT.YourColumn,'|') DS1
     CROSS APPLY dbo.DelimitedSplit8K_LEAD(DS1.Item,'=') DS2
GROUP BY DS1.ItemNumber;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...