Как найти конкретное ЗНАЧЕНИЕ для конкретного STRING местоположения в разных строках - PullRequest
0 голосов
/ 14 июня 2019

У меня жало вот так
, Х, х, у, х, х, О, х, у
что соответствует его значениям в другом укусе, как это
0 ~ 1 ~ Ь ~~ г ~ Х ~ 1 ~ 7.
Значение «O» может переключать свою позицию в строке, как и значение в другой строке.
Значение «O» находится на 6-й позиции, поэтому ожидаемый результат будет «XY».
Первая строка всегда начинается с «,» перед каждым значением. Вторая строка начинается сначала со значения, за которым следует «~».
«O» - это заданное значение, которое не изменится, поэтому мне всегда нужно находить данное значение для позиции, где «O» находится во второй строке.

Это то, что я ожидаю:

, Х, х, у, х, х, О, х, у
0 ~ 1 ~ Ь ~~ г ~ Х ~ 1 ~ 7
* +1014 * O = XY


, Х, О, у, х, х, у, х, у
0 ~ 1 ~ Ь ~~ г ~ Х ~ 1 ~ 7

O = 1
* тысяча двадцать-один * Спасибо.

Ответы [ 2 ]

1 голос
/ 16 июня 2019

Это решение на основе JSON:

Редактировать: самый быстрый подход (необходим v2016) -> удалено решение на основе XQuery

DECLARE @string1 VARCHAR(1000) = ',x,x,x,x,x,O,x,y',
        @string2 VARCHAR(1000) = '0~1~b~~z~XY~1~7';

SELECT s2.[value]
FROM OPENJSON('["' + REPLACE(@string1,',','","') + '"]') AS s1
CROSS APPLY OPENJSON('["' + REPLACE(@string2,'~','","') + '"]') AS s2 
WHERE s1.[value]='O' AND s2.[key]=s1.[key]-1;

Идея вкратце: Заменяя разделители, мы преобразуем строки с разделителями в JSON-массивы и используем возможности JSON для поиска позиции элемента и используем эту позицию для выборки другого элемента.

UPDATE

Я провел несколько тестов производительностии обнаружил, что решение XQuery работает довольно плохо.С небольшой строкой максимум из 10 элементов это нормально, но с более длинными строками (протестировано с 100 элементами) это работает довольно медленно ...

Тестовый код, если интересно:

DECLARE @i INT=1
       ,@CountElements INT=5 --Use higher values here
       ,@CountRows INT=500;

DECLARE @tbl TABLE(ID INT IDENTITY, i1t90 INT, s1 VARCHAR(500),s2 VARCHAR(500));

DECLARE @TemplateString VARCHAR(1000);
WHILE @i<@CountElements
BEGIN
    SET @TemplateString = CONCAT(@TemplateString,@i,'~');
    SET @i=@i+1;
END

SET @i=1;
WHILE @i<@CountRows
BEGIN
    INSERT INTO @tbl(i1t90, s1,s2) 
    SELECT
     ISNULL(NULLIF(@i%@CountElements,0),@CountElements)
    ,STUFF(REPLICATE(',x',@CountElements),(ISNULL(NULLIF(@i%@CountElements,0),@CountElements))*2,1,'O')
    ,CONCAT(@TemplateString,@i)

    SET @i=@i+1;
END

DECLARE @d DATETIME2=SYSUTCDATETIME();

SELECT t.*
      ,B.PosO
      ,A.y.value('(/y[sql:column("B.PosO")]/text())[1]','nvarchar(100)') AS FoundValue
INTO #t1
FROM @tbl t 
CROSS APPLY
(       
    SELECT (SELECT CAST('<x>' + REPLACE(s1,',','</x><x>') + '</x>' AS XML))
          ,(SELECT CAST('<y>' + REPLACE(s2,'~','</y><y>') + '</y>' AS XML))) AS A(x,y)
CROSS APPLY(SELECT A.x.value('count(/x[. << (/x[text()="O"])[1]])','int')) B(PosO);

SELECT 'XML based new', DATEDIFF(MILLISECOND,@d,SYSUTCDATETIME());

SET @d=SYSUTCDATETIME();

SELECT *
INTO #t2
FROM @tbl
CROSS APPLY dbo.delimitedSplit8K(s2,'~') AS s
WHERE s.itemNumber = 
(
  SELECT TOP (1) s1.itemNumber -- TOP (1) until we know about dupicates
  FROM   dbo.delimitedSplit8K(s1,',') AS s1
  WHERE  s1.item = 'O'
)-1;

SELECT 'Splitter based',DATEDIFF(MILLISECOND,@d,SYSUTCDATETIME());

SELECT * FROM #t1;
SELECT * FROM #t2;

DROP TABLE #t1;
DROP TABLE #t2;

Подход на основе сплиттера в моих тестах примерно в 8 раз быстрее ...

ОБНОВЛЕНИЕ 2: JSON-сплиттер (нужен v2016 +)

Этот подход примерно в 5 раз быстрее, чем на основе сплиттераподход:

SELECT t.*
      ,s2.[key] +1 AS PosO --zero based index
      ,s2.[value] AS FoundValue  
INTO #t3
FROM @tbl t
CROSS APPLY OPENJSON('["' + REPLACE(s1,',','","') + '"]') AS s1
CROSS APPLY OPENJSON('["' + REPLACE(s2,'~','","') + '"]') AS s2 
WHERE s1.[value]='O' AND s2.[key]=s1.[key]-1;
1 голос
/ 14 июня 2019

Получите копию DelimitedSplit8K , тогда вы можете сделать это:

DECLARE @string1 VARCHAR(1000) = ',x,x,y,x,x,O,x,y',
        @string2 VARCHAR(1000) = '0~1~b~~z~XY~1~7';

DECLARE @search VARCHAR(1000) = 'O'; -- best as a variable/parameter

SELECT *
FROM dbo.delimitedSplit8K(@string2,'~') AS s
WHERE s.itemNumber = 
(
  SELECT TOP (1) s2.itemNumber -- TOP (1) until we know about dupicates
  FROM   dbo.delimitedSplit8K(@string1,',') AS s2
  WHERE  s2.item = @search
)-1;

Возвраты:

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