Создание индекса по конкретному значению JSON внутри массива объектов - PullRequest
0 голосов
/ 17 сентября 2018

Итак, допустим, у меня есть столбец varchar в таблице с такой структурой, как:

{
   "Response":{
      "DataArray":[
         {
            "Type":"Address",
            "Value":"123 Fake St"
         },
         {
            "Type":"Name",
            "Value":"John Doe"
         }
      ]
   }
}

И я хочу создать постоянный вычисляемый столбец в поле «Значение» элемента массива «DataArray»который содержит поле типа, равное «имени».(Надеюсь, я объяснил это правильно. По сути, я хочу проиндексировать имена людей в этой структуре.)

Проблема в том, что, в отличие от других объектов json, я не могу использовать функцию JSON_VALUE впростой способ извлечь указанное значение.Я понятия не имею, если это можно сделать, я баловался с JSON_QUERY, но до сих пор я не знаю, что делать.

Любые идеи и помощь приветствуются.Спасибо!

Ответы [ 3 ]

0 голосов
/ 27 сентября 2018

Вы можете достичь этого, используя функцию:

CREATE FUNCTION dbo.my_func(@s NVARCHAR(MAX))
RETURNS NVARCHAR(100)
WITH SCHEMABINDING
AS
BEGIN
   DECLARE @r NVARCHAR(100);

   SELECT @r = Value 
   FROM OPENJSON(@s,'$.Response.DataArray')  
   WITH ([Type] NVARCHAR(100) '$.Type', [Value] NVARCHAR(100) '$.Value')
   WHERE [Type] = 'Name';

   RETURN @r;
END;

Таблица определения:

CREATE TABLE tab(
  val NVARCHAR(MAX) CHECK (ISJSON(val) = 1),
  col1 AS dbo.my_func(val) PERSISTED        -- calculated column
);

Пример данных:

INSERT INTO tab(val) VALUES (N'{
   "Response":{
      "DataArray":[
         {
            "Type":"Address",
            "Value":"123 Fake St"
         },
         {
            "Type":"Name",
            "Value":"John Doe"
         }
      ]
   }
}');

CREATE INDEX idx ON tab(col1);   -- creating index on calculated column

SELECT * FROM tab;

дБ<> демоверсия скрипки

0 голосов
/ 28 сентября 2018

Вы можете использовать скалярную функцию, как писал @Lukasz Szozda - это хорошее решение для этого.Проблема, однако, со скалярными пользовательскими функциями T-SQL в вычисляемых столбцах заключается в том, что они разрушают производительность любого запроса, к которому относится таблица. Замедляется не только изменение (вставка, обновление, удаление) данных, но и любые планы выполнения запросов, которыеИспользование этой таблицы не может использовать план параллельного выполнения. Это имеет место, даже если на вычисляемый столбец нет ссылки в запросе .Даже построения индекса теряют способность использовать план параллельного выполнения.Обратите внимание на эту статью: Еще одна причина, по которой скалярные функции в вычисляемых столбцах - это плохая идея от Эрика Дарлинга.

Это не так красиво, но, если важна производительность, вы получите результаты.нужно без недостатков скалярного UDF.

CREATE TABLE dbo.jsonStrings
(
  jsonString VARCHAR(8000) NOT NULL, 
  nameTxt AS (
    SUBSTRING(
      SUBSTRING(jsonString,
        CHARINDEX('"Value":"',jsonString,
          CHARINDEX('"Type":"Name",',jsonString,
            CHARINDEX('"DataArray":[',jsonString)+12))+9,8000),1,
      CHARINDEX('"', 
        SUBSTRING(jsonString,
          CHARINDEX('"Value":"',jsonString,
            CHARINDEX('"Type":"Name",',jsonString,
              CHARINDEX('"DataArray":[',jsonString)+12))+9,8000))-1)) PERSISTED
);

INSERT dbo.jsonStrings(jsonString)
VALUES
('{
   "Response":{
      "DataArray":[
         {
            "Type":"Address",
            "Value":"123 Fake St"
         },
         {
            "Type":"Name",
            "Value":"John Doe"
         }
      ]
   }
}');

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

Вторым (и лучшим, но более сложным) решением было бы взять логику пути json из скалярного UDF Лукаша Шозды и поместить ее в CLR.Скалярные пользовательские функции T-SQL, при правильном написании, не имеют вышеупомянутых проблем, которые имеют скалярные пользовательские функции T-SQL.

0 голосов
/ 17 сентября 2018

Вы можете использовать вычисляемый столбец с PATINDEX и индексом, который:

CREATE TABLE foo (a varchar(4000), a_ax AS (IIF(PATINDEX('%bar%', a) > 0, SUBSTRING(a, PATINDEX('%bar%', a), 42), '')))

CREATE INDEX foo_x ON foo(a_ax)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...