Таблица фильтра на основе данных из объекта JSON - PullRequest
0 голосов
/ 10 октября 2018

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

У меня есть следующее TableA:

CREATE TABLE TableA (
   Id INT NULL,
   Value1 VARCHAR(25) NULL,
   Value2 VARCHAR(25) NULL
);

INSERT INTO TableA (Id, Value1, Value2) values (1, 'test1', 'new1')
INSERT INTO TableA (Id, Value1, Value2) values (1, 'test1', 'new2')
INSERT INTO TableA (Id, Value1, Value2) values (null, null, 'test3')
INSERT INTO TableA (Id, Value1, Value2) values (2, 'myvalue1', 'newvalue')

Параметр JSON является динамическим и представляет одно или несколько имен и значений столбцов из приведенной выше таблицы.

DECLARE @Filter NVARCHAR(MAX)
SET @Filter=N'{
  "Id": 2, 
  "Value1": "myvalue1",
  "Value2": "newvalue"
}'

И я извлекаю данные из json и inner join с помощью TableA, чтобы получить нужный мне вывод:

...
;WITH cte AS
(
   SELECT * FROM OPENJSON(@Filter)
   WITH(Id INT, 
        Value1 VARCHAR(25),
        Value2 VARCHAR(25))
)
SELECT a.* FROM cte ct
INNER JOIN TableA a
  ON ct.Id = a.Id
INNER JOIN TableA b
  ON ct.Value1 = b.Value1
INNER JOIN TableA c
  ON ct.Value2 = c.Value2

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

Если я пропущу следующие фильтры, я больше не будуполучить желаемый результат из-за inner join.

SET @Filter=N'{
  "Id": 2, 
}'
...
SET @Filter=N'{
  "Id": 2, 
  "Value1": "test1"
}'
...
SET @Filter=N'{
  "Value1": "test1, 
  "Value1": "new2"
}'
...etc
  1. Есть ли способ динамически выбрать все объекты из json, который имеет значения, и пропустить нули?Или какие-либо другие предложения о том, как я могу решить эту проблему?
  2. Есть ли способ проверить, есть ли в json какие-либо объекты?Основываясь на документации, есть только одна функция ISJSON, которая проверяет, чтобы убедиться, что она в правильном формате.Однако, если я передам: SET @Filter=N'{}' это допустимый объект json, но он пустой.

SQLFIDDLE

Ответы [ 2 ]

0 голосов
/ 10 октября 2018

Вы можете попробовать это:

SELECT a.* 
FROM TableA a
WHERE (a.Id IS NULL AND JSON_VALUE(@Filter,N'$.Id') IS NULL OR a.Id = ISNULL(CAST(JSON_VALUE(@Filter,N'$.Id') AS INT),a.Id))
  AND (a.Value1 IS NULL AND JSON_VALUE(@Filter,N'$.Value1') IS NULL OR a.Value1 = ISNULL(JSON_VALUE(@Filter,N'$.Value1'),a.Value1))
  AND (a.Value2 IS NULL AND JSON_VALUE(@Filter,N'$.Value2') IS NULL OR a.Value2 = ISNULL(JSON_VALUE(@Filter,N'$.Value2'),a.Value2));

Хитрость в том, чтобы заменить NULL фактическим значением столбца ...

0 голосов
/ 10 октября 2018

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

where (value1 is null or field1 = value1)

Это устраняет возможность явного выбора field1 is nullиспользуя фильтр, и вам нужно будет взорвать ваш оператор select на два выражения для параметра:

--SELECT * FROM TableA

DECLARE @Filter NVARCHAR(MAX)
SET @Filter=N'{
  "Id": 1, 
  "Value1": "test1",
  "Value2": "new2"
}'
;WITH cte AS
(
  SELECT * FROM OPENJSON(@Filter)
  WITH(Id INT, 
       Value1 VARCHAR(25),
       Value2 VARCHAR(25))
)
SELECT a.* FROM cte filter
INNER JOIN TableA a
  ON     filter.Id = a.Id
     and (filter.Value1 is null or filter.Value1 = a.Value1)
     and (filter.Value2 is null or filter.Value2 = a.Value2)

Результат запроса

Id  Value1  Value2
1   test1   new2

Фильтрация с не установленными значениями

Если в вашем JSON отсутствует значение, оно не будет использоваться в качестве критерия фильтра:

--SELECT * FROM TableA

DECLARE @Filter NVARCHAR(MAX)
SET @Filter=N'{
  "Id": 1, 
  "Value2": "new2"
}'
;WITH cte AS
(
  SELECT * FROM OPENJSON(@Filter)
  WITH(Id INT, 
       Value1 VARCHAR(25),
       Value2 VARCHAR(25))
)
SELECT a.* FROM cte filter
INNER JOIN TableA a
  ON     filter.Id = a.Id
     and (filter.Value1 is null or filter.Value1 = a.Value1)
     and (filter.Value2 is null or filter.Value2 = a.Value2)

Вывод SQL

Id  Value1  Value2
1   test1   new2
...