how can I store Json query in SQL? - sql

I have to write Json and I dont know how could i store that query in SQL Server
my code is this:
DECLARE #JsonData AS NVARCHAR(MAX) = (SELECT FID, Ftype, Fcount, Datetype, Fregion
FROM FoodSara_tbl
FOR JSON AUTO)
and if I write SELECT ISJSON(#JsonData ) it returns 1
how can I store Json query in SQL?
PS: I dont't want write it in SP

DECLARE #JsonData AS NVARCHAR(MAX) =
CAST((SELECT FID, Ftype, Fcount, Datetype, Fregion
FROM FoodSara_tbl
FOR JSON AUTO) AS NVARCHAR(max));
Because a query returns a dataset !... You need to specify that the single value returned in the dataset must be casted in string...

Related

Parse JSON in SQL

I'm looking to parse a single return in JSON into multiple rows.
The string is this -
{"policy_ids":["INZP2981-11000002","INZP-00001786","0AAAA01PC06"]}
I want to just parse this so that it is a row for each policy_ids. I've tried using OpenJSON WITH however I keep returning NULL values.
DECLARE #json NVARCHAR(MAX) ;
SET #json = N'{"policy_ids":["INZP2981-11000002","INZP-00001786","0AAAA01PC06"]}' ;
SELECT
*
FROM
OPENJSON(#json)
WITH (
policy_ids varchar(200) '$.policy_ids'
)
Help is appreciated.
You need a different statement to parse the $.policy_ids JSON array. You may try tou use OPENJSON() with default schema (without the WITH clause). In this case the result is a table with columns key, value and type and the value column returns the value of each item in the input array.
DECLARE #json NVARCHAR(MAX) ;
SET #json = N'{"policy_ids":["INZP2981-11000002","INZP-00001786","0AAAA01PC06"]}' ;
SELECT [value] AS policy_id
FROM OPENJSON(#json, '$.policy_ids')
Result:
policy_id
-----------------
INZP2981-11000002
INZP-00001786
0AAAA01PC06
If you want to use an explicit schema, the statement is:
SELECT *
FROM OPENJSON(#json, '$.policy_ids') WITH (
policy_id varchar(200) '$'
)

SQL - openjson to extract key from json

Below #json contains 3 data object within an array. After using OPENJSON to extract these objects to a Table variable, please see the output attached.
DECLARE #json NVARCHAR(MAX);
SET #json = N'[{"Container":"MSKU2913236","Seal":"ML-TH4773979","Size":"20","Temperature":"-20","TareWeight":"3.132","CreatedDate":"02-02-2018 00:00:00","Comment":null,"NetWeight":"21.445","TempRec#":null},{"Container":"MSKU3432702","Seal":"ML-TH4773972","Size":"20","Temperature":"-40","TareWeight":"2.872","CreatedDate":"02-02-2018 00:00:00","Comment":null,"NetWeight":"23.932","TempRec#":"TR12345"},{"Container":"MSKU4043053","Seal":"ML-TH4773973","Size":"20","Temperature":"-20","TareWeight":"2.995","CreatedDate":"02-02-2018 00:00:00","Comment":null,"NetWeight":"22.4","TempRec#":null}]';
DECLARE #ContainerTable TABLE(
[Key] NVARCHAR(100),
[Data] NVARCHAR(MAX)
);
INSERT INTO #ContainerTable
SELECT [key], [value] FROM OPENJSON(#json)
SELECT * FROM #ContainerTable
Output
Objective is to replace the Key column values with the Container property value from json in the Data column for all 3 rows.
Expected Output
Note: Expected output is hard coded and it only shows the one row but same is required for all rows.
You could use JSON_VALUE:
INSERT INTO #ContainerTable([Key], [Data])
SELECT JSON_VALUE([value],'$.Container'), [value]
FROM OPENJSON(#json);
DBFiddle Demo

SQL Server: set a variable with more than one possible value

I need your help. I have a command to update rows, this works if in a variable #ID contain one value.
DECLARE #ID nvarchar(100)
SET #ID = (select top 1 id from [SERVICES])
DECLARE #UPDATE nvarchar(max)
SET #UPDATE ='UPDATE SERVICES
SET SERVICES.options = t1.options
FROM SERVICES t
JOIN (SELECT *
FROM OPENQUERY([ORI], ''SELECT ID, options
FROM log
WHERE ID = ''''' + #ID + ''''' '')) t1 ON t1.id = t.id'
EXEC (#UPDATE)
but I need to update more than 1 rows.
If I specify a condition like this:
SET #ID = (SELECT id FROM [ReportSM].[dbo].[SERVICES])
I get an error:
Subquery returned more than 1 value.
How to fix it?
It sounds like you really want to pass a table valued parameter into the open query, but that's not supported. You can remove that filter and let the join take care of the update accuracy but that will result in a potentially much more expensive remote query than necessary. That solution would just look like this:
UPDATE
t
SET
t.options = t1.options
FROM
Services t
JOIN (SELECT ID, options FROM OPENQUERY([ORI], 'SELECT ID, options FROM
log')) t1 ON t1.id = t.id
However, if you have control over the ORI linked server, you could set up a linked server there back to your ReportSM server. That would let you create a view on your ORI server that contains all of the IDs from your [ReportSM].[dbo].[SERVICES] table which is what you are trying to filter your log table on. That means you could perform the ID filtering on the ORI side and then run a simpler update on the ReportSM side. Something like this on the ORI side:
CREATE VIEW vReportServiceIDs
AS
SELECT
ID
FROM
[ReportSM].[dbo].[SERVICES]
CREATE VIEW vReportServiceLogs
AS
SELECT
reportService.ID,
oriLog.options
FROM
vReportServiceIDs reportService
JOIN [log] oriLog ON reportService.ID = [log].ID
And then on your ReportSM side:
UPDATE
t
SET
t.options = t1.options
FROM
SERVICES t
JOIN (
SELECT
ID, options
FROM
OPENQUERY([ORI], 'SELECT ID, options FROM vReportServiceLogs')
If you do not have that kind of access to the ORI server and the logs table has too much data for you to just query it all and exclude what you don't need during the join, you might want to consider creating a cache of the logs table that you update from a job on the ReportSM server and then just joining on that during your update.
Option 1
In your current setup, you could pass #ID as a CSV to OPENQUERY such that WHERE IN would work.
WHERE ID = ' + #ID + '
could then be replaced with
WHERE ID IN (' + #IDs + ')'
Look here to convert your ID column into a CSV: SQL Server convert select a column and convert it to a string
Be aware of the limit on the length of the IN clause. See this https://dba.stackexchange.com/questions/14161/what-is-the-maximum-number-of-parameters-i-can-pass-using-the-sql-in-clause-in-s
Option 2
Since concatenating data directly into a query has SQL injection concerns, you could also look at a more structured approach of using FOR XML to convert the IDs into an xml fragment and passing that into OPENQUERY and within that reading the ids out using OPENXML.
If both your servers are SQL Server 2016 or above, you could also use JSON as your format for transferring the ids instead of XML. You would use FOR JSON to create a JSON array containing the ids and use OPENJSON on the destination SQL server to convert the JSON back into a rowset that you can join.
declare #json varchar(max) = (select id from [ReportSM].[dbo].[SERVICES] FOR JSON PATH)
This will generate a string like this
[{"id":1},{"id":2},{"id":3},{"id":4}]
You can add this into a variable in the query you are preparing and read it using below
SELECT ID
FROM OPENJSON (#json, '$')
WITH (ID IN '$.id')
Putting it together your query would look like this:
declare #json varchar(max) = (select id from [ReportSM].[dbo].[SERVICES] FOR JSON PATH)
DECLARE #UPDATE nvarchar(max)
SET #UPDATE ='UPDATE SERVICES
SET SERVICES.options = t1.options
FROM SERVICES t
JOIN (SELECT *
FROM OPENQUERY([ORI], ''DECLARE #json nvarchar(max) = ''''' + #json + '''''
SELECT ID, options
FROM log
WHERE ID IN (SELECT ID FROM OPENJSON (#json, ''$'') WITH (ID IN ''$.id'')))) t1 ON t1.id = t.id'
EXEC (#UPDATE)

Need help in parsing json string in SQL stored procedure and accessing its attribute's value

I want to parse json string coming from request, extract particular information from that string and then based on that information need to call relevant update statements.
In java service it would be bit tedious to do this task as need to send each parameter separately and call relevant update statements.
If I can do the same task in stored procedure then it would be efficient. is there any way I can parse this same json string in a SQL stored procedure and update corresponding fields of tables by value of related attributes ?
Sample json string is -
{"category1":{"field1":"value1","field2":"value2"}}
this I want to send as a parameter of stored procedure
and I want to call update statement to update fields of related table with value1 and value2.
How can I parse these values in stored procedure from json string that I pass as a parameter to it?
I know this would be better off as a comment but I currently don't have that many rep points..
With that said you could try comma-schema.
I noticed this article using it.. I think you could use it to do the same.
Basically create data like the above article then update as needed
Definitely you can use JSON in a Stored procedure. This is a best way to make your DB closer to REST APIs. Your Stored procedure can have input and output both as JSON. It is just that you have to put efforts in writing a good stored procedure. rather than exposing a random access to API/user for querying it directly
here is one of the example:
DECLARE #out VARCHAR(max) =''
EXEC csdm.your_sp
#input = <your_JSON_string>,
#output = #out OUTPUT
SELECT #out
Now to achieve this write your SP as
CREATE PROCEDURE dbo.your_sp
#input VARCHAR(max),
#output VARCHAR(max) OUTPUT
AS
PRINT 'PROC_START : dbo.your_sp'
-- Declare variables as needed
DECLARE #sp_output VARCHAR(max)
DECLARE #json_category VARCHAR(max)
DECLARE #json_category VARCHAR(max)
-- Validate JSON
IF(ISJSON(#input) = 0)
BEGIN
SET #sp_output = '{"status":"Error","errorTitle":"Invalid Input JSON","errorMessage":"JSON sent as input is Incorrect, please verify and fix"}'
END
ELSE
BEGIN
-- Process JSON if valid JSON provided
-- Option 1
INSERT INTO myTable
(Field1, Field2)
VALUES
(
SELECT [VALUE] FROM OPENJSON(#op, '$.category1') where [KEY] = 'field1',
SELECT [VALUE] FROM OPENJSON(#op, '$.category1') where [KEY] = 'field1'
)
SET #sp_output = '{"status":"Success", "message":"Record updated successfully"}'
-- Option 2 : Can have more validation for the data
SELECT #json_category = VALUE FROM OpenJson (#input, '$') WHERE [Key] = 'category1'
SELECT #json_field_value = VALUE FROM OpenJson (#json_category, '$') WHERE [Key] = 'field1'
IF(#json_category IS NOT NULL OR #json_category <> '') AND (#json_field_value IS NOT NULL OR #json_field_value <> '')
BEGIN
INSERT INTO myTable
(Field1, Field2)
VALUES
(
SELECT [VALUE] FROM OPENJSON(#op, '$.category1') where [KEY] = 'field1',
SELECT [VALUE] FROM OPENJSON(#op, '$.category1') where [KEY] = 'field1'
)
SET #sp_output = '{"status":"Success", "message":"Record updated successfully"}'
END
ELSE
BEGIN
SET #sp_output = '{"status":"Error","errorTitle":"Blank/Missing Input provided","errorMessage":"Critical / Mandatory data is missing in the input JSON"}'
END
END
-- Build Output or Error response
SET #output = #sp_output
PRINT 'PROC_END : dbo.your_sp'
RETURN
GO
This is just a sample to show how to use JSON, you can do a lot more in this additionally

Parsing non-standard XML in SQL Server with XTbl

I have a serialised piece of data in a column that I want to retrieve a single value from, in the following form:
<FirstNode>Something</><SecondNode>Something Else</>
I want to retrieve, for example, 'Something' from this in SQL Server. I've tried the following:
declare #data xml;
set #data = cast([my data source] as xml);
select #data.value('(/UserName)[1]','varchar(50)')
I'm probably way off with this, I don't have a huge deal of experience with parsing XML. Any help would be great.
Edit: I get the error
XML parsing: line 1, character 20, illegal qualified name character
Just use the CHARINDEX and SUBSTRING functions to get the data you want. Rolling my example into a function would probably be your best bet.
DECLARE #tbl TABLE(data VARCHAR(MAX))
INSERT INTO #tbl VALUES
('<FirstNode>Something</><SecondNode>Something Else</>'),
('<SecondNode>Something Else</><FirstNode>More Something</>'),
('<BadNoe>Something</><SecondNode>Something Else</>')
DECLARE #fnd VARCHAR(64)
DECLARE #end VARCHAR(64)
SET #fnd = '<FirstNode>'
SET #end = '</>'
SELECT SUBSTRING(a.[data], a.[start] + LEN(#fnd), a.[end] - (a.[start] + LEN(#fnd)))
FROM (SELECT data [data], CHARINDEX(#fnd, data, 0) [start], CHARINDEX(#end, data, CHARINDEX(#fnd, data, 0)) [end] FROM #tbl) a
WHERE a.[start] > 0