根据json对象的数据过滤表

时间:2018-10-10 05:05:51

标签: sql json sql-server-2017

我正在尝试使用JSON type作为存储过程的输入参数,对返回数据进行一些过滤。

我有以下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中动态选择具有值的所有对象并跳过null?或关于如何解决此问题的其他建议?
  2. 是否可以检查json中是否包含任何对象?根据文档,只有一个函数ISJSON会进行验证以确保其格式正确。但是,如果我通过:SET @Filter=N'{}',则它是有效的json对象,但为空。

SQLFIDDLE

2 个答案:

答案 0 :(得分:2)

您可以尝试以下方法:

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 ...

答案 1 :(得分:0)

我知道这并不是一个令人满意的答案,但是我在这种情况下使用的方法是将每个可选字段与:

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