Как эффективно проверить массив JSON на значения в T-SQL - PullRequest
0 голосов
/ 22 января 2019

Я хочу найти несколько строк, в которых массив JSON содержит определенное значение или значения.Иногда все совпадающие элементы должны соответствовать (AND с), иногда только некоторые (OR с), а иногда и комбинации обоих (AND с и OR с).

Этов Microsoft SQL Server 2017.

Я попытался сделать оператор AS в select, но в результате псевдоним, созданный для подзапроса, не был распознан позже в подзапросе.

Приведенный ниже пример работает , выглядит просто безумно и имеет дублирование кода.

Как бы я указал SELECT VALUE FROM OPENJSON(JsonData, '$.categories' только один раз?Или, может быть, есть какой-то другой способ сделать это?

DECLARE @TestTable TABLE
(
  Id int, 
  JsonData nvarchar(4000)
);

INSERT INTO @TestTable
    VALUES 
    (1,'{"categories":["one","two"]}'),
    (2,'{"categories":["one"]}'),
    (3,'{"categories":["two"]}'),
    (4,'{"categories":["one","two","three"]}');

SELECT [Id]
  FROM @TestTable
  WHERE ISJSON(JsonData) = 1
  -- These two lines are the offending parts of code
  AND 'one' in (SELECT VALUE FROM OPENJSON(JsonData, '$.categories'))
  AND 'two' in (SELECT VALUE FROM OPENJSON(JsonData, '$.categories'));

Формат таблицы не может измениться, хотя я могу добавить вычисляемые столбцы - при необходимости.

1 Ответ

0 голосов
/ 22 января 2019

Ну, я не уверен, поможет ли это вам ...

Это может помочь преобразовать вложенный массив в производную таблицу, чтобы использовать его в качестве CTE. Проверьте это:

DECLARE @TestTable TABLE
(
  Id int, 
  JsonData nvarchar(4000)
);

INSERT INTO @TestTable
    VALUES 
    (1,'{"categories":["one","two"]}'),
    (2,'{"categories":["one"]}'),
    (3,'{"categories":["two"]}'),
    (4,'{"categories":["one","two","three"]}');

- это запрос

WITH JsonAsTable AS
(
    SELECT Id 
          ,JsonData
          ,cat.*
    FROM @TestTable tt
    CROSS APPLY OPENJSON(tt.JsonData,'$.categories') cat
)
SELECT *
FROM JsonAsTable

Подход очень близок к запросу, который вы создали сами. В результате получается таблица с одной строкой для каждой записи массива. Форма Id - это повторяющийся ключ группировки, key - порядковый номер в массиве, а value - это одно из слов, которые вы ищете.

В своем запросе вы можете использовать JsonAsTable, как если бы вы использовали любую другую таблицу в этом месте.

Но - вместо повторяющихся FROM OPENJSON запросов - вам понадобятся повторяющиеся предикаты EXISTS() ...

Хакерское решение может быть таким:

SELECT Id
      ,JsonData
      ,REPLACE(REPLACE(REPLACE(JsonData,'{"categories":[','",'),']}',',"'),'","',',')
FROM @TestTable

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

...