I am writing a stored procedure to insert these values into a table. Always my table column name will be the key and column data will be the value in the JSON.
DECLARE #json NVARCHAR(MAX) = N'[
{
"name": "abcd",
"id": 12,
"feelings": {
"happy": 0,
"angry": 1,
"sad": 1
}
},
{
"name": "abcdf",
"id": 14,
"feelings": {
"happy": 0,
"angry": 1,
"sad": 1
}
}
]'
DECLARE #id INT;
DECLARE #last_name NVARCHAR(50);
SET #id =10;
SET #last_name = 'Mike'
Example:
INSERT INTO Table([name],[id],[lastname],[happy],[angry],[sad])
VALUES ("abcd",#id,#last_name,0,1,1)
How can I achieve this for any JSON format? Always the JSON key should be mapped to the column name. The insert statement should be able to insert all the entries from the JSON. Only the key inside the feelings will change. All others remain the same.
I need to include data from the JSON as well as static declared data in the insert query.Does OPENJSON allow including static data in WITH().
Please help me with this.
I think that dynamic statement should be your first option:
JSON:
DECLARE #json nvarchar(max) = N'[
{
"name": "abcd",
"id": 12,
"feelings": {
"happy": 0,
"angry": 1,
"sad": 1
}
},
{
"name": "abcdf",
"id": 14,
"feelings": {
"happy": 0,
"angry": 1,
"sad": 1
}
}
]'
Statement:
DECLARE #stm nvarchar(max)
DECLARE #columns nvarchar(max)
DECLARE #schema nvarchar(max)
DECLARE #id int
SET #id = 10
SELECT
#columns = STRING_AGG(QUOTENAME([key]), N','),
#schema = STRING_AGG(CONCAT(QUOTENAME([key]), N' int ''$.feelings."', [key], '"'''), N',')
FROM OPENJSON(#json, '$[0].feelings')
SELECT #stm = CONCAT(
N'INSERT INTO InputTable ([id],[name],',
#columns,
N') SELECT #id,[name],',
#columns,
N' FROM OPENJSON(#json) WITH ([name] varchar(100) ''$."name"'',',
#schema,
N')'
)
PRINT #stm
EXEC sp_executesql #stm, N'#json nvarchar(max), #id int', #json, #id
Generated dynamic statement:
INSERT INTO InputTable ([id],[name],[happy],[angry],[sad])
SELECT #id,[name],[happy],[angry],[sad]
FROM OPENJSON(#json) WITH (
[name] varchar(100) '$."name"',
[happy] int '$.feelings."happy"',
[angry] int '$.feelings."angry"',
[sad] int '$.feelings."sad"'
)
I think you're looking for something like this. This opens and flattens the JSON
declare
#json nvarchar(max)=N'[
{
"name": "abcd",
"id": 12,
"feelings": {
"happy": 0,
"angry": 1,
"sad": 1
}
},
{
"name": "abcdf",
"id": 14,
"feelings": {
"happy": 0,
"angry": 1,
"sad": 1
}
}
]';
INSERT INTO Table([name],[happy],[angry],[sad])
select oj.[name], f.*
from openjson(#json) with (name nvarchar(4000),
id int,
feelings nvarchar(max) as json) oj
cross apply
openjson(oj.feelings) with (happy int,
angry int,
sad int) f;
Results
name id happy angry sad
abcd 12 0 1 1
abcdf 14 0 1 1
Not sure I got your question correctly, but if you need to get data from JSON based on columns existing in table which you want to pass by name then you need to have dynamic sql. So here's an example of how you can do it using sys.columns view:
drop table if exists dbo.temp_data
create table dbo.temp_data (name nvarchar(128), happy bit, angry bit, sad bit);
----------------------------------------------------------------------------------------------------
declare #table_name nvarchar(256) = 'dbo.temp_data'
declare #data nvarchar(max) = '[
{
"name": "abcd",
"id": 12,
"feelings": {
"happy": 0,
"angry": 1,
"sad": 1
}
},
{
"name": "abcdf",
"id": 14,
"feelings": {
"happy": 0,
"angry": 1,
"sad": 1
}
}
]';
declare #stmt nvarchar(max);
declare #stmt_part1 nvarchar(max);
declare #stmt_part2 nvarchar(max);
select
#stmt_part1 = concat(isnull(#stmt_part1 + ',', ''),c.name),
#stmt_part2 = concat(isnull(#stmt_part2 + ',', ''),'json_value(o.value, ''$.feelings.',c.name,''')')
from sys.columns as c
where
c.object_id = object_id(#table_name) and
c.name <> 'name'
set #stmt = concat('
insert into ',#table_name,' (name,',#stmt_part1,')
select
json_value(o.value, ''$.name'') as name,',#stmt_part2,'
from openjson(#data) as o
');
exec sys.sp_executesql
#stmt,
N'#data nvarchar(max)',
#data = #data;
----------------------------------------------------------------------------------------------------
select * from dbo.temp_data
I don't know which version of Sql Server you're using so I'm not sure if you can use string_agg system function so I've used pretty standard trick to aggregate column names into string.
Related
I have the following JSON data:
declare #json nvarchar(max)=
'
[{
"images": [{
"key": "c:\\stapler\\booktest\\gray00024.jp2",
"imageNumber": 1
}],
"instrumentNumber": 94109416
},
{
"images": [{
"key": "c:\\stapler\\booktest\\gray00025.jp2",
"imageNumber": 1
},
{
"key": "c:\\stapler\\booktest\\gray00026.jp2",
"imageNumber": 2
}
],
"instrumentNumber": 94109417
},
{
"images": [{
"key": "c:\\stapler\\booktest\\gray00027.jp2",
"imageNumber": 1
},
{
"key": "c:\\stapler\\booktest\\gray00028.jp2",
"imageNumber": 2
}
],
"instrumentNumber": 94109418
}
]'
I am trying to pull the key and imageNumber from each of these records.
I have tried this query which will give me the instrument number, but gives NULL skey and imageNumber values:
select * from openjson (#json)
with(
instrumentNumber nvarchar(100) '$.instrumentNumber',
skey nvarchar(500) '$.images.key',
imageNumber nvarchar(500) '$.images.imageNumber')
Can anyone tell me what I am doing wrong?
Because you have a nested array (images) you need to extract those values in another openjson which you can then cross apply to the original:
select a.instrumentNumber, b.skey, b.imageNumber
from openjson (#json)
with (
instrumentNumber nvarchar(100) '$.instrumentNumber',
images nvarchar(max) as json
) a
cross apply openjson (a.images)
with (
skey nvarchar(500) '$.key',
imageNumber nvarchar(500) '$.imageNumber'
) b
Output for your sample data
instrumentNumber skey imageNumber
94109416 c:\stapler\booktest\gray00024.jp2 1
94109417 c:\stapler\booktest\gray00025.jp2 1
94109417 c:\stapler\booktest\gray00026.jp2 2
94109418 c:\stapler\booktest\gray00027.jp2 1
94109418 c:\stapler\booktest\gray00028.jp2 2
Demo on dbfiddle.uk
I have a string column in an SQL-Server table on Azure which contains the following data:
{
"status": "success",
"data": [
{
"name": "Jane",
"type": 0
},
{
"name": "John",
"type": 0
}
]
}
How can it be transformed into a comma-separated string containing "Jane, John"?
Here how to achieve this via a snippet of some of my older code, you should be able to loop through the table and do this for each row. There may be a quicker way of doing it but this will work.
DECLARE #JSON NVARCHAR(200) = '{"status": "success", "data": [{"name": "Jane", "type": 0},{"name": "John", "type": 0}]}',
#result nvarchar(max) = ''
SELECT #result = #result + [value] + N', '
FROM (
SELECT DISTINCT data.value
FROM OPENJSON(#JSON, '$.data') as jsondata
CROSS APPLY OPENJSON(jsondata.value) as data
WHERE data.[key] = 'name') a
select #result = substring(#result, 1, (LEN(#result)-1))
select #result
I have JSON like below:
{
"property": {
"commonProperty": "abc",
"Items": [
{
"ID": 1,
"Name": "a"
},
{
"ID": 2,
"Name": "a"
},
{
"ID": 3,
"Name": "b"
}
]
}
}
And what I want to achieve is to update Names to "c" where it's currently "a" using SQL Server (so I want to have result like below).
{
"property": {
"commonProperty": "abc",
"Items": [
{
"ID": 1,
"Name": "c"
},
{
"ID": 2,
"Name": "c"
},
{
"ID": 3,
"Name": "b"
}
]
}
}
As far as I know I cannot use JSON_MODIFY because it does not handles queries inside it's arguments and OPENJSON cannot be updated. Is there any method I can use?
EDIT note: added common property above Items.
You may try one of the following options:
Parse the '$.property.Items' JSON array as table using OPENJSON(), make an update, output the table's content as JSON using FOR JSON and modify the original JSON using JSON_MODIFY():
Build a dynamic statement. You can modify the input JSON using JSON_MODIFY() and the appropriate path. The path needs to be defined as a literal or from SQL Server 2017 as a variable, but using a wildcard is not possible (e.g. the statement SELECT #json = JSON_MODIFY(#json, '$.property.Items[0].Name', N'c') modifies the first item in the Items JSON array).
JSON:
DECLARE #json nvarchar(max) = N'{
"property":{
"commonProperty":"abc",
"Items":[
{
"ID":1,
"Name":"a"
},
{
"ID":2,
"Name":"a"
},
{
"ID":3,
"Name":"b"
}
]
}
}'
Statement (that parses the JSON as a table, modifies the table and outputs the table's content as JSON):
SELECT #json = JSON_MODIFY(
#json,
'$.property.Items',
(
SELECT
ID AS 'ID',
CASE WHEN Name = N'a' THEN N'c' ELSE Name END AS 'Name'
FROM OPENJSON(#json, '$.property.Items') WITH (ID int, Name nvarchar(50))
FOR JSON PATH
)
)
Dynamic statement:
DECLARE #stm nvarchar(max)
SET #stm = (
SELECT N'SET #json = JSON_MODIFY(#json, ''$.property.Items[' + [key] + N'].Name'', N''c''); '
FROM OPENJSON(#json, '$.property.Items')
WHERE JSON_VALUE([value], '$.Name') = N'a'
FOR XML PATH('')
)
PRINT #stm
EXEC sp_executesql #stm, N'#json nvarchar(max) OUTPUT', #json OUTPUT
I need JSON returned from a SQL Server scalar function.
I wrote this query inside SSMS
SELECT
Id AS [Expense.Id],
Amount AS [Expense.Amount],
StudentName AS [Expense.StudentName]
FROM
[dbo].[Expenses]
FOR JSON PATH, Root('Expenses')
Here is result (EXACTLY WHAT I WANTED)
"Expenses": [
{
"Expense": {
"Id": "43838475-5BBC-4C2A-A1E9-85F9E55298D3",
"Amount": 0.0000000e+000,
"StudentName": "Carter"
}
},
{
"Expense": {
"Id": "38AC0403-5DCF-42E1-A103-5D33DB905F57",
"Amount": 0.0000000e+000,
"StudentName": "Louis"
}
},
{
"Expense": {
"Id": "5E6EB81E-C988-4D7C-98AB-FA814CFF875A",
"Amount": 0.0000000e+000,
"StudentName": "David"
}
}
Now then all I have to do is wrap it in a function:
CREATE FUNCTION [dbo].[get_all_json]
(#input nvarchar)
RETURNS nvarchar
AS
BEGIN
DECLARE #return nvarchar
SET #return = (SELECT
Id AS [Expense.Id],
Amount AS [Expense.Amount],
StudentName AS [Expense.StudentName]
FROM
[dbo].[Expenses]
FOR JSON PATH, Root('Expenses'))
RETURN #return
END
Now I call it in SSMS:
SELECT TRIM( dbo.get_all_json('1')) json_fm_func;
And I get this result back:
SELECT TRIM( dbo.get_all_json('1')) json_fm_func;
What went wrong?
You need to change nvarchar to nvarchar(max)
create function [dbo].[get_all_json] (#input nvarchar(max))
--the argument (#input) is never used. you can create your function without argument.
returns nvarchar(max) as
begin
declare #return nvarchar(max)
set #return = (SELECT Id as [Expense.Id]
,Amount As [Expense.Amount]
,StudentName As [Expense.StudentName]
FROM [dbo].[Expenses] FOR JSON PATH, Root('Expenses'))
return #return
end
If I do this I can get the first value in the array. But how can I get all of the values in the list ?
SELECT
JSON_VALUE('{"Distributor": [5030, 4000, 1231]}', '$.Distributor[0]') AS result;
SELECT value
FROM OPENJSON('{"Distributor": [5030, 4000, 1231]}','$.Distributor')
'$.Distributor' is the 'start path' to start looking for an array
You can take look at this article:
https://learn.microsoft.com/fr-fr/sql/relational-databases/json/json-data-sql-server?view=sql-server-2017
Using function Openjson and Outer apply
Example provided:
DECLARE #json NVARCHAR(MAX)
SET #json =
N'[
{ "id" : 2,"info": { "name": "John", "surname": "Smith" }, "age": 25 },
{ "id" : 5,"info": { "name": "Jane", "surname": "Smith", "skills": ["SQL", "C#", "Azure"] }, "dob": "2005-11-04T12:00:00" }
]'
SELECT *
FROM OPENJSON(#json)
WITH (id int 'strict $.id',
firstName nvarchar(50) '$.info.name', lastName nvarchar(50) '$.info.surname',
age int, dateOfBirth datetime2 '$.dob',
skills nvarchar(max) '$.info.skills' as json)
outer apply openjson( skills )
with ( skill nvarchar(8) '$' )
EDIT Code with provided json :
DECLARE #json NVARCHAR(MAX)
SET #json = N'{"Distributor": [5030, 4000, 1231]}'
SELECT Distributor
FROM OPENJSON(#json)
WITH (Distributors nvarchar(max) '$.Distributor' as json)
outer apply openjson( Distributors )
with ( Distributor int '$' )
RESULT :
Distributor
5030
4000
1231