38

You know about the new JSON_ support in SQL Server 2016 so let's say I have this data in a row

{
  "BaseBoarding": 1,
  "PriceLineStrategy": "PerPersonPerNight",
  "Currency": "EUR",
  "BasePriceLineList": [
    {
      "RoomTypeId": 1,
      "PeriodId": 1,
      "Price": 10.0
    },
    {
      "RoomTypeId": 1,
      "PeriodId": 2,
      "Price": 100.0
    },
    {
      "RoomTypeId": 1,
      "PeriodId": 3,
      "Price": 190.0
    },
    {
      "RoomTypeId": 2,
      "PeriodId": 1,
      "Price": 280.0
    },
    {
      "RoomTypeId": 2,
      "PeriodId": 2,
      "Price": 310.0
    },
    {
      "RoomTypeId": 2,
      "PeriodId": 3,
      "Price": 340.0
    }
  ]
}

How do I get the number of items of "BasePriceLineList" in the most performant way, preferably using the built-in JSON support?

Need to write something like this:

SELECT JSON_ARRLEN(JsonDataCol, '$.BasePriceline') FROM MyTable
WHERE Id = 1

and get 6 as the result.

Mihail Shishkov
  • 14,129
  • 7
  • 48
  • 59

5 Answers5

32

Using a table instead of a variable:

SELECT count(priceLineLists.RoomTypeId)
FROM Mytable
CROSS APPLY OPENJSON (JsonDataCol, N'$.BasePriceLineList')
  WITH (
    RoomTypeId int)
      AS priceLineLists
rich kalasky
  • 628
  • 4
  • 8
28

The hypothetical SQL statement:

SELECT JSON_ARRLEN(JsonDataCol, '$.BasePriceline') FROM MyTable

Can be done by the actual statement:

SELECT (SELECT COUNT(*) FROM OPENJSON(JsonDataCol, '$.BasePriceline')) FROM MyTable
Michael Erickson
  • 4,217
  • 2
  • 23
  • 10
12

You can convert it to a data set and then count the rows:

DECLARE @JSON NVARCHAR(4000) = N'{
  "BaseBoarding": 1,
  "PriceLineStrategy": "PerPersonPerNight",
  "Currency": "EUR",
  "BasePriceLineList": [
    {
      "RoomTypeId": 1,
      "PeriodId": 1,
      "Price": 10.0
    },
    {
      "RoomTypeId": 1,
      "PeriodId": 2,
      "Price": 100.0
    },
    {
      "RoomTypeId": 1,
      "PeriodId": 3,
      "Price": 190.0
    },
    {
      "RoomTypeId": 2,
      "PeriodId": 1,
      "Price": 280.0
    },
    {
      "RoomTypeId": 2,
      "PeriodId": 2,
      "Price": 310.0
    },
    {
      "RoomTypeId": 2,
      "PeriodId": 3,
      "Price": 340.0
    }
  ]
}'

select COUNT(*) 
FROM OPENJSON(@json, N'$.BasePriceLineList')
WITH (RoomTypeID varchar(100) '$.RoomTypeId')
dfundako
  • 8,022
  • 3
  • 18
  • 34
5

This basic need came up for me a few times when doing some ad-hoc data review. So I went ahead and created a tiny scalar function to do this pretty generically. Few assumptions built in, you might need to use an isnull and/or use json_value to pull out a nested array you are trying to examine. Also, I really don't know what the performance impact of this would be at any scale, I've only needed to do this on a few dozen records at a time. Just thought I'd share in case anyone else lands here looking for a fairly generic way of doing this.

NOTE: Used a couple hacky "tricks" in this such as making sure the function throws an error on an invalid JSON array even though throw isn't allowed inside a function. The extra divide by zero is in case anyone has really lax implicit conversion settings and just a pattern I use in other places where a string return would have been valid.

create function array_length (@array nvarchar(max))
returns int as begin
  if (@array is null or isjson(@array) != 1
      or left(@array, 1) + right(@array, 1) <> '[]')
    return 'Invalid JSON array provided to array_length' + (1/0)
  return (select count(*) from openjson(@array))
end
Brian Jorden
  • 1,166
  • 10
  • 9
1

Lot of digging around and my conclusion is to use this. Remove count if you want to see the queried elements as they were found. Working with SQL Server 2019

SELECT 
COUNT(JSON_QUERY(JsonObject, '$.[0].Region')) AS RegionCount
FROM YourTable
Netferret
  • 604
  • 4
  • 15
  • 5
    This approach is unreliable. The following returns 1, instead of the expected 0: `select count(json_query('[]', 'strict $'))`. – user2864740 Mar 10 '21 at 22:37