Reading JSON string and find the max value as integer - sql

I have a JSON string as follows:
DECLARE #json nvarchar(max)
SET #json = '{"value": [
{
"AEDAT": "20211110"
},
{
"AEDAT": "20211110"
},
{
"AEDAT": "20211110"
},
{
"AEDAT": "20211112"
},
{
"AEDAT": "20211112"
},
{
"AEDAT": "20211112"
}
]}';
Now I want to read this JSON in SQL Server using OPENJSON() and find the MAX value for each AEDAT. For this, I am using the following query:
SELECT MAX(value)
FROM OPENJSON(#json, '$.value')
The above query is returning a row with key value pair as below:
{"AEDAT":"20211112"}
My objective is to get only 20211112 as integer.
How to achieve this?

If you want to get the max value as integer, you need to use OPENJSON() with explicit schema (the WITH clause with columns definitions). This schema depends on the structure of the parsed JSON (in your case it's a JSON array):
SELECT MAX(AEDAT) AS MaxAEDAT
FROM OPENJSON(#json, '$.value') WITH (
AEDAT int '$.AEDAT'
)
If the parsed values are dates, you may try a different statement:
SELECT MAX(TRY_CONVERT(date, AEDAT, 112)) AS MaxAEDAT
FROM OPENJSON(#json, '$.value') WITH (
AEDAT varchar(8) '$.AEDAT'
)

OPENJSON without explicit schema, gives you the value column which, in your example, will contain an object such as {"AEDAT": "20211110"} having type = 5. Use JSON_VALUE on that object:
select max(cast(json_value(j.value, '$.AEDAT') as int))
from openjson(#json, '$.value') as j

Related

How would I convert this JSON stored in a database column into a table with columns and rows?

Given the below JSON data and table that holds the data, how can I query the values and write to a new table with rows and columns split?
Basic table that contains the JSON:
CREATE TABLE BI.DataTable
(
JsonDataText VARCHAR(MAX)
);
JSON data:
{
"datatable": {
"data": [
[
"ZSFH",
"99999",
"2022-08-31",
571106
],
[
"ZSFH",
"99999",
"2022-07-31",
578530
],
[
"ZSFH",
"99999",
"2022-06-30",
582233
],
[
"ZSFH",
"99999",
"2022-05-31",
581718
]
]
}
}
When I use the JSON_VALUE function, I get a null for each column.
SELECT
JSON_VALUE (JsonDataText, '$.data[0]') AS MetricCode,
JSON_VALUE (JsonDataText, '$.data[1]') AS RegionID,
JSON_VALUE (JsonDataText, '$.data[2]') AS ReportingPeriod,
JSON_VALUE (JsonDataText, '$.data[3]') AS MetricValue
FROM BI.DataTable
WHERE ISJSON(JsonDataText) > 0
Using OPENJSON() with the appropriate columns definitions and an additioinal APPLY operator is a possible approach:
SELECT j.*
FROM DataTable d
OUTER APPLY OPENJSON(d.JsonDataText, '$.datatable.data') WITH (
MetricCode varchar(4) '$[0]',
RegionID varchar(5) '$[1]',
ReportingPeriod varchar(10) '$[2]',
MetricValue int '$[3]'
) j
WHERE ISJSON(d.JsonDataText) = 1
Result:
MetricCode
RegionID
ReportingPeriod
MetricValue
ZSFH
99999
2022-08-31
571106
ZSFH
99999
2022-07-31
578530
ZSFH
99999
2022-06-30
582233
ZSFH
99999
2022-05-31
581718
Note, that the reasons for the NULL values returned from your current statement are:
JSON_VALUE() extracts a scalar value from a JSON string, but the $.datatable.data part of the stored JSON is a JSON array with JSON arrays as items, so in this situation you need to use JSON_QUERY().
The $.data[0] path expression is wrong.
The following example (using JSON_QUERY() and the correct path) extracts an item from the $.datatable.data JSON array:
SELECT
JSON_QUERY(JsonDataText, '$.datatable.data[0]') AS MetricCode,
JSON_QUERY(JsonDataText, '$.datatable.data[1]') AS RegionID,
JSON_QUERY(JsonDataText, '$.datatable.data[2]') AS ReportingPeriod,
JSON_QUERY(JsonDataText, '$.datatable.data[3]') AS MetricValue
FROM DataTable
WHERE ISJSON(JsonDataText) > 0

Query for retrieve matching json Objects as a list

Assume i have a table called MyTable and this table have a JSON type column called myjson and this column have next value as a json array hold multiple objects, for example like next:
[
{
"budgetType": "CF",
"financeNumber": 1236547,
"budget": 1000000
},
{
"budgetType": "ENVELOPE",
"financeNumber": 1236888,
"budget": 2000000
}
]
So how i can search if the record has any JSON objects inside its JSON array with financeNumber=1236547
Something like this:
SELECT
t.*
FROM
"MyTable",
LATERAL json_to_recordset(myjson) AS t ("budgetType" varchar,
"financeNumber" int,
budget varchar)
WHERE
"financeNumber" = 1236547;
Obviously not tested on your data, but it should provide a starting point.
with a as(
SELECT json_array_elements(myjson)->'financeNumber' as col FROM mytable)
select exists(select from a where col::text = '1236547'::text );
https://www.postgresql.org/docs/current/functions-json.html
json_array_elements return setof json, so you need cast.
Check if a row exists: Fastest check if row exists in PostgreSQL

Edit json with array of objects error, it's replacing the array with one object

I have a JSON column like this
[
{
"JoinedTime": "2021-04-13T20:09:40.654Z",
"LeftTime": "2021-04-13T20:09:53.368Z",
},
{
"JoinedTime": "2021-04-13T20:09:40.654Z",
"LeftTime": null,
},
]
And I have to update all null 'LeftTime' properties to GETUTCDATE(), so change that one 'null' value to the current GETUTCDATE().
I've gotten this far
UPDATE JoinedLeft
SET JsonColumn = JSON_MODIFY(js.[value], '$.LeftTime', FORMAT(GETUTCDATE(), 'yyyy-MM-dd"T"HH:mm:ss"Z"'))
FROM JoinedLeft JL
CROSS APPLY OPENJSON(JL.JsonColumn) AS js
WHERE
JSON_VALUE(js.[value], '$.LeftTime') IS NULL AND
JSON_VALUE(js.[value], '$.JoinedTime') IS NOT NULL
But it just replaces the column with just the object that I wanted to edit, instead of editing the object and saving the array again.
Can someone help me?
When you parse a JSON array with OPENJSON() and default schema (without the WITH clause), the result is a table with rows for each item in the parsed JSON array. This explains the enexpected results from the UPDATE statement. I don't think that JSON_MODIFY() supports wildcards as path parameter, so one possible option is to parse, modify and build the JSON array again:
Table:
SELECT JsonColumn
INTO JoinedLeft
FROM (VALUES
('[
{"JoinedTime": "2021-04-13T20:09:40.654Z","LeftTime": "2021-04-13T20:09:53.368Z"},
{"JoinedTime": "2021-04-14T21:09:40.654Z", "LeftTime": null}
]'),
('[
{"JoinedTime": "2021-05-14T21:09:40.654Z", "LeftTime": null}
]')
) t (JsonColumn)
Statement:
UPDATE JL
SET JL.JsonColumn = V.JsonColumn
FROM JoinedLeft JL
CROSS APPLY (
SELECT
JoinedTime,
COALESCE(LeftTime, FORMAT(GETUTCDATE(), 'yyyy-MM-dd"T"HH:mm:ss"Z"')) AS LeftTime
FROM OPENJSON(JL.JsonColumn, '$') WITH (
JoinedTime varchar(24) '$.JoinedTime',
LeftTime varchar(24) '$.LeftTime'
) AS JsonColumn
FOR JSON PATH
) V (JsonColumn);
Result:
JsonColumn
[{"JoinedTime":"2021-04-13T20:09:40.654Z","LeftTime":"2021-04-13T20:09:53.368Z"},{"JoinedTime":"2021-04-14T21:09:40.654Z","LeftTime":"2021-05-18T12:12:35Z"}]
[{"JoinedTime":"2021-05-14T21:09:40.654Z","LeftTime":"2021-05-18T12:12:35Z"}]

Select part from the values in SQL

I have such problem/question. I am trying to extract data from database, but only part. The real example is:
{
"email":"bla#gmail.com",
"addinfo":{
"invoice_id":"1F5FspmpyfQ"
},
"cardholder":"blabla",
"masked_pan":"123456XXXXXX1234"
}
I need to receive only 1F5FspmpyfQ, all between {"invoice_id": " and "},.
You can use Postgres' JSON functions:
select the_column::jsonb -> 'addinfo' ->> 'invoice_id' as invoice_id
from the_table;
-> returns a json object with the specified key and ->> returns the key's value as a text (rather than jsonb)
You can use JSON functions in SQL Server, but JSON support was not introduced until SQL Server 2016:
DECLARE #json NVARCHAR(MAX);
SET #json = '{
"email":"blablabla",
"addinfo":{
"invoice_id":"1F5FspmpyfQ"
},
"cardholder":"bla bla",
"masked_pan":"12345XXXXXX1234"
}';
SELECT JSON_VALUE(#json, '$.addinfo.invoice_id');

OpenJson using a wildcard

I have a SQL query using OPENJSON to import JSON data into a table. My problem is that the data I need is nested. How can I use a wildcard in the JSON path to get what I need?
SELECT #Set =
BulkColumn FROM OPENROWSET
(BULK 'Sets.json', DATA_SOURCE = 'MyAzureJson', SINGLE_BLOB) JSON;
INSERT INTO [Sets]
SELECT [name]
FROM OPENJSON(#Set)
WITH(
[name] nvarchar(50) '$.*.name'
)
my json file is set up like this..
{
"testOne" : {
name: "nameOne"
},
"testTwo : {
name: "nameTwo"
}
}
the error I'm getting with everything I try..
JSON path is not properly formatted. Unexpected character '*' is found at position 2.
I've tried . * [] and nothing works
As far as I know there is no support for wildcards in OPENJSON.
Instead you can do a workaround by ignoring the field name in your search. Use JSON_VALUE for this.
INSERT INTO [Sets]
SELECT
JSON_VALUE([value], '$.name')
FROM
OPENJSON(#Set)
Explanation: If you don't define the variables of OPENJSON inside a WITH clause and instead do a simple SELECT * FROM OPENJSON(#Set) query, you will get a result with key, value and type columns (see example output below). Because key contains your problematic field name, you can ignore that part and just look into the value column of the data.
[key] [value] [type]
----- ------- ------
testOne { name: "nameOne" } 5
testTwo { name: "nameTwo" } 5