В таблице SQL Server, как фильтровать записи на основе поиска JSON по столбцу, имеющему значения JSON - PullRequest
0 голосов
/ 05 апреля 2019

Я сталкиваюсь с проблемой при фильтрации записей в таблице SQL Server 2017, в которой есть столбец VARCHAR со значениями типа JSON:

Примеры строк таблицы со значениями столбцов JSON:

Row # 1. {"Department":["QA"]}   
Row # 2. {"Department":["DEV","QA"]}    
Row # 3. {"Group":["Group 2","Group 12"],"Cluster":[Cluster 11"],"Vertical": 
    ["XYZ"],"Department":["QAT"]}          
Row # 4. {"Group":["Group 20"],"Cluster":[Cluster 11"],"Vertical":["XYZ"],"Department":["QAT"]}

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

Пример входного параметра JSON для запроса:

1. `'{"Department":["QA"]}'` -> This should return Row # 1 as well as Row # 2.   
2. `'{"Group":["Group 2"]}'` -> This should return only Row # 3.

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


Примечание. Это похоже на jsonb PostgreSQL, как показано ниже:
Предложение фильтра PostgreSQL:

TableName.JSONColumnName @> '{"Department":["QA"]}'::jsonb

Проведя исследования в Интернете, я обнаружил возможность OPENJSON, доступную в SQL Server, которая работает следующим образом.

Пример примера OPENJSON:

SELECT * FROM
tbl_Name UA
CROSS APPLY OPENJSON(UA.JSONColumnTags)
WITH ([Department] NVARCHAR(500) '$.Department', [Market] NVARCHAR(300) '$.Market', [Group] NVARCHAR(300) '$.Group'       
   ) AS OT
WHERE
OT.Department in ('X','Y','Z')
and OT.Market in ('A','B','C')

Но проблема этого подхода заключается в том, что если в будущем возникнет необходимость поддерживать какой-либо новый тег в JSON (например, «Область»), его также необходимо будет добавить в каждую хранимую процедуру, в которой реализована эта логика.

Существуют ли какие-либо возможности SQL Server 2017, которые мне не хватает, или какой-либо динамический способ реализовать то же самое?

1 Ответ

0 голосов
/ 05 апреля 2019

Единственная вещь, которую я мог бы представить в качестве опции при использовании OPENJSON, это разбить вашу строку поиска на ее пару ключ-значение, разбить вашу таблицу, в которой хранится json, который вы хотите найти, в его пару ключ-значение и присоединиться.

Существуют ограничения, о которых следует знать:

  1. Это решение не будет работать с вложенными массивами в вашем json
  2. Поиск будет ИЛИ, а не И.То есть, если я передам несколько «Отделов», которые я искал, например, «{» Отдел »: [« QA »,« DEV »]}», он вернет строки с любым из значений, а не те, которые содержат только оба.

Вот рабочий пример:

DECLARE @TestData TABLE
    (
        [TestData] NVARCHAR(MAX)
    );
--Load Test Data
INSERT INTO @TestData (
                          [TestData]
                      )
VALUES ( '{"Department":["QA"]}' )
     , ( '{"Department":["DEV","QA"]}' )
     , ( '{"Group":["Group 2","Group 12"],"Cluster":["Cluster 11"],"Vertical": ["XYZ"],"Department":["QAT"]}' )
     , ( '{"Group":["Group 20"],"Cluster":["Cluster 11"],"Vertical":["XYZ"],"Department":["QAT"]}' );

--Here is the value we are searching for
DECLARE @SeachJson NVARCHAR(MAX) = '{"Department":["QA"]}';

DECLARE @SearchJson TABLE
    (
        [Key] NVARCHAR(MAX)
      , [Value] NVARCHAR(MAX)
    );

--Load the search value into a temp table as its key\value pair.
INSERT INTO @SearchJson (
                            [Key]
                          , [Value]
                        )
            SELECT      [a].[Key]
                      , [b].[Value]
            FROM        OPENJSON(@SeachJson) [a]
            CROSS APPLY OPENJSON([a].[Value]) [b];

--Break down TestData into its key\value pair and then join back to the search table.
SELECT     [TestData].[TestData]
FROM       (
               SELECT      [a].[TestData]
                         , [b].[Key]
                         , [c].[Value]
               FROM        @TestData [a]
               CROSS APPLY OPENJSON([a].[TestData]) [b]
               CROSS APPLY OPENJSON([b].[Value]) [c]
           ) AS [TestData]
INNER JOIN @SearchJson [srch]
    ON [srch].[Key] COLLATE DATABASE_DEFAULT = [TestData].[Key]
       AND [srch].[Value] = [TestData].[Value];

, который дает следующие результаты:

TestData
-----------------------------
{"Department":["QA"]}
{"Department":["DEV","QA"]}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...