I have a JSON api
https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&retmode=json&id=17784783,19505939,217873815946,30166592,30310060,30575739,30837262
I want to send data to a stored procured and because of time I had hired two database programmers.
My question: is the only way to parse a JSON object in SQL Server 2016 is with a cursor? In the past I was parsing the JSON object in a .NET WEB API.
Using
For Each elements As JToken In result
now it's
INSERT INTO #temp_values (value)
SELECT value
FROM OPENJSON (#json, '$.result')
WHERE [key] <> 'uids'
DECLARE #MyCursor CURSOR;
DECLARE #values NVARCHAR(MAX);
BEGIN
SET #MyCursor = CURSOR FOR
SELECT value FROM #temp_values
OPEN #MyCursor
FETCH NEXT FROM #MyCursor INTO #values
Related
JSON_MODIFY does not support many base types in the 3rd argument. How fix it?
DECLARE #info NVARCHAR(200)='{"name":"John","skills":["C#","SQL"]}'
SELECT JSON_MODIFY(#info, '$.code', NEWID())
SELECT JSON_MODIFY(#info, '$.date', GETDATE())
SELECT JSON_MODIFY(#info, '$.cost', CAST(1 AS money))
Msg 8116, Level 16, State 1, Line 3
Argument data type uniqueidentifier is invalid for argument 3 of
json_modify function.
Msg 8116, Level 16, State 1, Line 5
Argument data type datetime is invalid for argument 3 of json_modify
function.
Msg 8116, Level 16, State 1, Line 8
Argument data type money is invalid for argument 3 of json_modify
function.
Try use my dbo.JSON_MODIFY function that solved problem
CREATE FUNCTION dbo.JSON_MODIFY(#expression nvarchar(max), #path nvarchar(max), #newValue sql_variant)
RETURNS nvarchar(max)
AS
BEGIN
DECLARE #tempJson nvarchar(max) = (SELECT #newValue AS col1 FOR JSON PATH, WITHOUT_ARRAY_WRAPPER)
RETURN JSON_MODIFY(#expression, #path, JSON_VALUE(#tempJson, '$.col1'))
END
GO
DECLARE #info NVARCHAR(100)='{"name":"John","skills":["C#","SQL"]}'
PRINT dbo.JSON_MODIFY(#info, '$.code', NEWID())
PRINT dbo.JSON_MODIFY(#info, '$.date', GETDATE())
PRINT dbo.JSON_MODIFY(#info, '$.cost', CAST(1 AS money))
GO
Output results:
{"name":"John","skills":["C#","SQL"],"code":"85543240-38C5-4647-B555-4388ADAD71F0"}
{"name":"John","skills":["C#","SQL"],"date":"2019-10-03T16:16:10.600"}
{"name":"John","skills":["C#","SQL"],"cost":"1.0000"}
I can think of a few reasons why updating JSON in SQL is a bad idea starting with the configuration options of those that consume the json. If you use need to be able to round-trip the JSON and you use something like NewtonSoft default settings you would need to cast/ format a date string in a particular way
select format(GetUtcDate(),'yyyy-MM-dd''T''HH:mm:ss.fff')+'Z'
in your sample, you should probably use if you use .net to read the data when it leaves your database... in any way you need to make sure you align your database with those that consume the data and, in my use-case use format to make sure the data does not generate corrupt JSON.
DECLARE #info NVARCHAR(100)='{"name":"John","skills":["C#","SQL"]}'
in your modify this would look like this
SELECT JSON_MODIFY(#info, '$.date', format(GetUtcDate(),'yyyy-MM-dd''T''HH:mm:ss.fff')+'Z')
I am building a testcafe web automation project with a data-driven framework. I am using NPM/node.jS/ with Visual Studio Code. I have a JSON File and a SQL query, I want to point the where clause of the SQL query to the JSON data. This is very new to me, any suggestions are welcome.
I saw that there is an NPM JSON-SQL Node.JS library, but I have not used it, any example will help me.
Json file:
[
{
venid='ABC'
status='Open'
},
{
venid='IGH'
status='Closed'
},
SQL query:
// running the query and query will take data from the json file
Select *
From table
Where VendorId = <jsondata>
and Inventorystatus = <jsonData>
I'm not sure if I understand your question correctly, but if you want to parse a JSON data using SQL Server, you should use JSON capabilities, which are introduced in SQL Server 2016. Most of the scripting languages have enough capabilities to wotk with JSON format, so you should pass JSON data directly to SQL Server.
Next is a basic example, which you may use as a starting point (note, that your JSON is not valid):
Table with data:
CREATE TABLE #Data (
VendorId nvarchar(3),
InventoryStatus nvarchar(10)
)
INSERT INTO #Data
(VendorId, InventoryStatus)
VALUES
(N'ABC', N'Open'),
(N'ABC', N'Closed'),
(N'IGH', N'Open'),
(N'IGH', N'Closed')
T-SQL:
-- Valid JSON
-- [{"venid":"ABC", "status":"Open"}, {"venid":"IGH", "status":"Closed"}]
DECLARE #json nvarchar(max)
-- Read JSON from file. Try to send JSON data directly to SQL Server.
-- Additional permissions are needed to execute next statement.
--SELECT #json = BulkColumn
--FROM OPENROWSET (BULK '<Path>\JsonData.json', SINGLE_CLOB) as j
-- Read JSON from variable
SELECT #json = N'[{"venid":"ABC", "status":"Open"}, {"venid":"IGH", "status":"Closed"}]'
-- Use JSON data in a statement
SELECT d.*
FROM #Data d
JOIN OPENJSON(#json) WITH (
VendorId nvarchar(3) '$.venid',
InventoryStatus nvarchar(10) '$.status'
) j ON (d.VendorId = j.VendorId) AND (d.InventoryStatus = j.InventoryStatus)
Output:
---------------------------
VendorId InventoryStatus
---------------------------
ABC Open
IGH Closed
Use case:
Application requires a subset of attributes, based on business rules
Example:
Some students do not require to enter in home address
Database : Oracle
Proposed implementation:
Build json object containing all possible attribute named pairs, then selectively remove specific named pairs
Issue:
Hoped to use native oracle function to remove the specified named pair.
e.g json_object.remove_attribute('home_address');
However Oracle do not appear to provide any such method.
Workaround : Convert json_object to VARCHAR2 string, and then use combination of INSTR and REPLACE to remove named pair.
Illustrative code:
DECLARE
CURSOR cur_student_json (p_s_ref IN VARCHAR2) IS
SELECT JSON_OBJECT(
,'s_surname' value s.s_surname
,'s_forename_1' value s.s_forename_1
,'s_home_address_1' value s.s_home_address_1
RETURNING VARCHAR2 ) student_json
FROM students s
WHERE s.s_ref = p_s_ref;
BEGIN
FOR x IN cur_student_json (p_s_ref) LOOP
vs_student_json:=x.student_json;
EXIT;
END LOOP;
-- Determine student type
vs_student_type:=get_student_type(p_s_ref);
-- Collect list of elements not required, based on student type
FOR x IN cur_json_inorout(vs_student_type) LOOP
-- Remove element from the json
vs_student_json:=json_remove(vs_student_json,x.attribute);
END LOOP;
END;
/
Question:
There must be an elegant method to achieve requirement
Classify under RTFM. Needs Oracle 12.2
DECLARE
-- Declare an object of type JSON_OBJECT_T
l_obj JSON_OBJECT_T;
-- Declare cursor to build json object
CURSOR cur_student_json (p_s_ref IN VARCHAR2) IS
SELECT JSON_OBJECT(
,'s_surname' value s.s_surname
,'s_forename_1' value s.s_forename_1
,'s_home_address_1' value s.s_home_address_1
) student_json
FROM students s
WHERE s.s_ref = p_s_ref;
BEGIN
-- Initialise object
l_obj := JSON_OBJECT_T();
-- Populate the object
FOR x IN cur_student_json (p_s_ref) LOOP
l_obj:=JSON_OBJECT_T.parse(x.student_json);
EXIT;
END LOOP;
-- Determine student type
vs_student_type:=get_student_type(p_s_ref);
-- Collect list of elements not required, based on student type
FOR x IN cur_json_inorout(vs_student_type) LOOP
-- Remove element from the json
l_obj.remove(x.attribute);
END LOOP;
-- Display modified object
dbms_output.put_line(l_obj.stringify);
END;
/
I am now working to convert datetime object in multi-objects JSON array to insert into a table SQL server. The problem is the datetime object contains timezone sign '+' or '-' and 'T' for time as follow:
"2018-05-04T10:31:31.134+06:30"
I would like to insert directly the above value to DATETIME object in a table from SQL Server. At that time, the ERROR is
'Conversion failed when converting date and/or time from character
string.'
I already tried with the following way.
DECLARE #json NVARCHAR(MAX) = '{"EntryDateTime":"2018-05-04T10:31:31.134+06:30"}';
DECLARE #tmp AS NVARCHAR(MAX)
SET #tmp= CONVERT(datetime2(3), JSON_VALUE(#json,'$.EntryDateTime'))
SET #json = JSON_MODIFY(#json, '$.EntryDateTime', #tmp)
print #json
But it works only for one JSON object. I would like to convert datetimeoffset format of multi-object JSON array to datetime like
'[{"EntryDateTime":"2018-05-04T10:31:31.134+06:30"},{"EntryDateTime":"2018-05-05T09:13:00.134+06:30"}]'
I need to write a test for some download operation. This operation call procedure from MSSQL database, take result set and java make some stuf. For test I use hsqldb.
My procedure:
CREATE PROCEDURE map.Get1(IN packageName varchar(100),
IN downloadDate DATE)
READS SQL DATA DYNAMIC RESULT SETS 1 BEGIN ATOMIC
DECLARE result CURSOR WITH RETURN FOR SELECT * FROM map.tvschedule FOR READ ONLY;
OPEN result;
END
This procedure wan't work, i have an exception
call map.GET1('Genre','2018-03-10');
[42561][-5561] incompatible data type in conversion
java.lang.RuntimeException: org.hsqldb.HsqlException: incompatible data type
in conversion
But this(without date parameter) work well:
CREATE PROCEDURE map.Get1(IN packageName varchar(100))
READS SQL DATA DYNAMIC RESULT SETS 1 BEGIN ATOMIC
DECLARE result CURSOR WITH RETURN FOR SELECT * FROM map.tvschedule FOR READ ONLY;
OPEN result;
END
call map.GET1('Genre');
first needed row
second needed row
I am not going to use input parameter, but i need this procedure to be looking i am going to.
My question is How to use date input parameter with hsqldb procedures?
UPDATE1:
I used TO_DATE and now it works well, but i have no data in my result set, my java code is:
try (CallableStatement callableStatement = connection.prepareCall("{ call
map.GetGenreProtocol( ?, ? ) }")) {
callableStatement.setString(1, packageName);
callableStatement.setDate(2, date);
callableStatement.execute();
ResultSet resultSet = callableStatement.getResultSet();
while (resultSet.next()) {
Interval Interval = new Interval();
Interval.setDuration(resultSet.getInt("duration"));
Interval.setMappingTargetId(resultSet.getInt("mappingTargetId"));
Interval.setGenreId(resultSet.getInt("genreId"));
Interval.setStart(resultSet.getLong("start"));
Interval.setCategoryId(resultSet.getInt("categoryId"));
Interval.setCategoryName(resultSet.getString("categoryName"));
Interval.setGenreName(resultSet.getString("genreName"));
Interval.setDescription(resultSet.getString("description"));
Intervals.add(Interval);
}
}
Use the TO_DATE function.
For example:
call map.GET1('Genre', TO_DATE('2018-03-10', 'YYYY-MM-DD'));
I guess you need to create a function that returns a table instead of a procedure:
CREATE FUNCTION map.Get1(IN packageName VARCHAR(100),
IN downloadDate DATE)
RETURNS TABLE(.....)
READS SQL DATA
BEGIN ATOMIC
....
END;