web-dev-qa-db-fra.com

Obtenir la longueur du tableau JSON dans SQL Server 2016

Vous connaissez la nouvelle prise en charge JSON_ dans SQL Server 2016, alors disons que j'ai ces données d'affilée

{
  "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
    }
  ]
}

Comment obtenir le nombre d'éléments de "BasePriceLineList" de la manière la plus performante, en utilisant de préférence le support JSON intégré?

Besoin d'écrire quelque chose comme ça:

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

et obtenez 6 comme résultat.

14
Mihail Shishkov

Utiliser une table au lieu d'une variable:

SELECT count(priceLineLists.RoomTypeId)
FROM Mytable
CROSS APPLY OPENJSON (JsonDataCol, N'$.BasePriceLineList')
  WITH (
    RoomTypeId int)
      AS priceLineLists
18
rich kalasky

Vous pouvez le convertir en un ensemble de données, puis compter les lignes:

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')
9
dfundako

Ce besoin de base est venu pour moi à quelques reprises lors de l'examen de données ad hoc. J'ai donc continué et créé une minuscule fonction scalaire pour le faire de façon assez générique. Peu d'hypothèses intégrées, vous devrez peut-être utiliser un isnull et/ou utiliser json_value pour extraire un tableau imbriqué que vous essayez d'examiner. De plus, je ne sais vraiment pas quel serait l'impact sur les performances à n'importe quelle échelle, je n'ai eu besoin de le faire que sur quelques dizaines d'enregistrements à la fois. Je pensais juste partager au cas où quelqu'un d'autre atterrirait ici à la recherche d'un moyen assez générique de le faire.

REMARQUE: utilisé quelques "astuces" hacky dans ce cas, par exemple en s'assurant que la fonction génère une erreur sur un tableau JSON non valide même si throw n'est pas autorisé dans une fonction. La division supplémentaire par zéro est dans le cas où quelqu'un a des paramètres de conversion implicites vraiment laxistes et juste un modèle que j'utilise dans d'autres endroits où un retour de chaîne aurait été valide.

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
4
Brian Jorden