SQL Server Creating index on specific JSON value inside an object array

dauxcl2d  于 2023-08-02  发布在  其他
关注(0)|答案(3)|浏览(111)

So let's say I have a varchar column in a table with some structure like:

  1. {
  2. "Response":{
  3. "DataArray":[
  4. {
  5. "Type":"Address",
  6. "Value":"123 Fake St"
  7. },
  8. {
  9. "Type":"Name",
  10. "Value":"John Doe"
  11. }
  12. ]
  13. }
  14. }

And I want to create a persisted computed column on the "Value" field of the "DataArray" array element that contains a Type field that equals "Name". (I hope I explained that properly. Basically I want to index the people's names on that structure).

The problem is that, unlike with other json objects, I can't use the JSON_VALUE function in a straightforward way to extract said value. I've no idea if this can be done, I've been dabbling with JSON_QUERY but so far I've no idea what to do.

Any ideas and help appreciated. Thanks!

dgiusagp

dgiusagp1#

You could achieve it using function:

  1. CREATE FUNCTION dbo.my_func(@s NVARCHAR(MAX))
  2. RETURNS NVARCHAR(100)
  3. WITH SCHEMABINDING
  4. AS
  5. BEGIN
  6. DECLARE @r NVARCHAR(100);
  7. SELECT @r = Value
  8. FROM OPENJSON(@s,'$.Response.DataArray')
  9. WITH ([Type] NVARCHAR(100) '$.Type', [Value] NVARCHAR(100) '$.Value')
  10. WHERE [Type] = 'Name';
  11. RETURN @r;
  12. END;

Defining table:

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

Sample data:

  1. INSERT INTO tab(val) VALUES (N'{
  2. "Response":{
  3. "DataArray":[
  4. {
  5. "Type":"Address",
  6. "Value":"123 Fake St"
  7. },
  8. {
  9. "Type":"Name",
  10. "Value":"John Doe"
  11. }
  12. ]
  13. }
  14. }');
  15. CREATE INDEX idx ON tab(col1); -- creating index on calculated column
  16. SELECT * FROM tab;

db<>fiddle demo

展开查看全部
qvk1mo1f

qvk1mo1f2#

You could use a computed column with PATINDEX and index that:

  1. CREATE TABLE foo (a varchar(4000), a_ax AS (IIF(PATINDEX('%bar%', a) > 0, SUBSTRING(a, PATINDEX('%bar%', a), 42), '')))
  2. CREATE INDEX foo_x ON foo(a_ax)
5hcedyr0

5hcedyr03#

You could use a scalar function as @Lukasz Szozda posted - it's a good solution for this. The problem, however, with T-SQL scalar UDFs in computed columns is that they destroy the performance of any query that table is involved in. Not only does data modification (inserts, updates, deletes) slow down, any execution plans for queries that involve that table cannot leverage a parallel execution plan. This is the case even when the computed column is not referenced in the query. Even index builds lose the ability to leverage a parallel execution plan. Note this article: Another reason why scalar functions in computed columns is a bad idea by Erik Darling.

This is not as pretty but, if performance is important than this will get you the results you need without the drawbacks of a scalar UDF.

  1. CREATE TABLE dbo.jsonStrings
  2. (
  3. jsonString VARCHAR(8000) NOT NULL,
  4. nameTxt AS (
  5. SUBSTRING(
  6. SUBSTRING(jsonString,
  7. CHARINDEX('"Value":"',jsonString,
  8. CHARINDEX('"Type":"Name",',jsonString,
  9. CHARINDEX('"DataArray":[',jsonString)+12))+9,8000),1,
  10. CHARINDEX('"',
  11. SUBSTRING(jsonString,
  12. CHARINDEX('"Value":"',jsonString,
  13. CHARINDEX('"Type":"Name",',jsonString,
  14. CHARINDEX('"DataArray":[',jsonString)+12))+9,8000))-1)) PERSISTED
  15. );
  16. INSERT dbo.jsonStrings(jsonString)
  17. VALUES
  18. ('{
  19. "Response":{
  20. "DataArray":[
  21. {
  22. "Type":"Address",
  23. "Value":"123 Fake St"
  24. },
  25. {
  26. "Type":"Name",
  27. "Value":"John Doe"
  28. }
  29. ]
  30. }
  31. }');

Note that, this works well for the structure you posted. It may need to be tweaked depending on what the JSON does and can look like.

A second (and better but more complex) solution would be to take the json path logic from Lukasz Szozda's scalar UDF and get it into a CLR. T-SQL scalar UDFs, when written correctly, do not have the aforementioned problems that T-SQL scalar UDFs do.

展开查看全部

相关问题