【问题标题】:SQL LIKE query on JSON data对 JSON 数据的 SQL LIKE 查询
【发布时间】:2019-11-29 19:41:23
【问题描述】:

我将 JSON 数据(无架构)存储在 SQL Server 列中,需要对其运行搜索查询。

例如(不是实际数据)

[
 {
   "Color":"Red",
   "Make":"Mercedes-Benz"  
 },
 {
   "Color":"Green",
   "Make":"Ford"  
 },
]

SQL Server 2017 具有 JSON_XXXX 方法,但它们适用于已知架构。在我的例子中,对象的模式没有精确定义并且可能会改变。

目前要搜索列,例如找到 Make=Mercedes-Benz。我正在使用搜索短语“%\"Make\":\"Mercedes-Benz\"%"。如果使用确切的品牌名称,这非常有效。我希望用户也能够使用部分名称进行搜索,例如只需输入“Benz”或“merc”。

是否可以使用适合我的通配符构建 SQL 查询?还有其他选择吗?

【问题讨论】:

  • 您可以在不定义数据的情况下使用OPENJSON,但是从中获取有用的数据是很困难的。样本数据和预期结果会很好
  • 这是非结构化数据的问题。那是你唯一的问题。如果你解决了这个问题,所有其他问题都会消失。接受 JSON 的 RDMS 无法解决这个问题,MongoDB 之类的东西也无法解决。

标签: c# json sql-server linq-to-sql


【解决方案1】:

一种可能的方法是将OPENJSON 与默认架构一起使用两次。使用默认架构,OPENJSONreturns 包含列 keyvaluetype 的表,您可以将它们用于您的 WHERE 子句。

表:

CREATE TABLE #Data (
   Json nvarchar(max)
)
INSERT INTO #Data
   (Json)
VALUES
   (N'[
 {
   "Color":"Red",
   "Make":"Mercedes-Benz"  
 },
 {
   "Color":"Green",
   "Make":"Ford",
   "Year": 2000
 }
]')

声明:

SELECT 
   j1.[value]
   -- or other columns 
FROM #Data d
CROSS APPLY OPENJSON(d.Json) j1
CROSS APPLY OPENJSON(j1.[value]) j2
WHERE 
   j2.[key] LIKE '%Make%' AND
   j2.[value] LIKE '%Benz%'

输出:

--------------------------
value
--------------------------
{
   "Color":"Red",
   "Make":"Mercedes-Benz"  
 }

【讨论】:

    【解决方案2】:

    你可以用 ',' 分割 json 并像这样搜索:

    WHERE EXISTS (SELECT *  
                FROM STRING_SPLIT(json_data, ',')  
               WHERE value LIKE  '%\"Make\":%'
                 AND value LIKE  '%Benz%' 
               );
    

    【讨论】:

      【解决方案3】:

      如果您碰巧运行的是不支持内置 JSON 函数(如 OPENJSON())的旧版本 SQL Server,则可以使用类似于以下的 SQL。

      您可以在http://sqlfiddle.com/#!18/dd7a5 尝试测试此 SQL

      注意:此 SQL 假定您正在搜索的键仅在每个记录/JSON 对象文字中出现一次(换句话说,您仅在每个记录/数据库行中存储具有唯一键的 JSON 对象文字)。另请注意,SELECT 查询是丑陋的,但它有效。

      /* see http://sqlfiddle.com/#!18/dd7a5 to test this online*/
      /* setup a test data table schema */
      CREATE TABLE myData (
         [id] [int] IDENTITY(1,1) NOT NULL,
         [jsonData] nvarchar(4000)
        CONSTRAINT [PK_id] PRIMARY KEY CLUSTERED 
      (
          [id] ASC
      )
      );
      
      /* Insert some test data */
      INSERT INTO myData
         (jsonData)
      VALUES
         ('{
         "Color":"Red",
         "Make":"Mercedes-Benz"
       }');
       
       INSERT INTO myData
         (jsonData)
      VALUES
         (
         '{
         "Color":"White",
         "Make":"Toyota",
         "Model":"Prius",
         "VIN":"123454321"
       }');
      
      INSERT INTO myData
         (jsonData)
      VALUES
         (
         '{
         "Color":"White",
         "Make":"Mercedes-Benz",
         "Year": 2009
       }');
       
       INSERT INTO myData
         (jsonData)
      VALUES
         (
         '{
         "Type":"Toy",
         "Color":"White",
         "Make":"Toyota",
         "Model":"Prius",
         "VIN":"99993333"
       }');
      
      /* This select statement searches the 'Make' keys, within the jsonData records, with values LIKE '%oyo%'. This statement will return records such as 'Toyota' as the Make value. */
      SELECT id, SUBSTRING(
              jsonData
              ,CHARINDEX('"Make":', jsonData) + LEN('"Make":')
              ,CHARINDEX(',', jsonData, CHARINDEX('"Make":', jsonData) + LEN('"Make":')) - CHARINDEX('"Make":', jsonData) - LEN('"Make":')
              ) as CarMake FROM myData
      WHERE 
      SUBSTRING(
              jsonData
              ,CHARINDEX('"Make":"', jsonData) + LEN('"Make":"')
              ,CHARINDEX('"', jsonData, CHARINDEX('"Make":"', jsonData) + LEN('"Make":"')) - CHARINDEX('"Make":"', jsonData) - LEN('"Make":"')
              ) LIKE '%oyo%'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-15
        • 1970-01-01
        • 2023-03-29
        • 2019-01-04
        • 2015-09-02
        • 2016-06-29
        相关资源
        最近更新 更多