SQL FOR JSON: Create line for each object - sql

I'm currently working on a JSON creation on a SQL Server 2016. For this, I use the FOR JSON function.
SELECT TOP 2
'12.00' AS [time]
,GUID AS [ID]
,'action value' AS [EVENT.ACTION]
,'category value' AS [EVENT.CATEGORY]
,'username' AS [user.name]
FROM TABLE_NAME
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
This piece of code creates me this:
{"time":"12.00","ID":"16AE8C15-084C-4C84-8F5D-0000193F8E74","EVENT":{"ACTION":"action value","CATEGORY":"category value"},"user":{"name":"username"}},{"time":"12.00","ID":"D5667AF4-5922-4D30-9C8A-00001AB928F6","EVENT":{"ACTION":"action value","CATEGORY":"category value"},"user":{"name":"username"}}
The problem is, every object gets displayed on line 1, but I would like to have one line per object.
This would look like this:
{"time":"12.00","ID":"16AE8C15-084C-4C84-8F5D-0000193F8E74","EVENT":{"ACTION":"action value","CATEGORY":"category value"},"user":{"name":"username"}},
{"time":"12.00","ID":"D5667AF4-5922-4D30-9C8A-00001AB928F6","EVENT":{"ACTION":"action value","CATEGORY":"category value"},"user":{"name":"username"}}
I have not found any snippets to do this. How can I create such a

If you need to build a separate JSON object for each row, you may try the following statement:
SELECT TOP 2
(
SELECT
'12.00' AS [time]
,GUID AS [ID]
,'action value' AS [EVENT.ACTION]
,'category value' AS [EVENT.CATEGORY]
,'username' AS [user.name]
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) AS JsonData
FROM TABLE_NAME
But, if the expected ouput is one JSON array (with or without array wrapper) for the entire table, the format of this output is controlled by FOR JSON AUTO. The visual representation of this output (one line per each JSON object) should be made in the presentation layer. Of course, as an additional option using T-SQL, a small string manipulation is a possible solution:
SELECT REPLACE (
(
SELECT TOP 2
'12.00' AS [time]
,GUID AS [ID]
,'action value' AS [EVENT.ACTION]
,'category value' AS [EVENT.CATEGORY]
,'username' AS [user.name]
FROM TABLE_NAME
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
),
'},{',
'},' + CHAR(10) + '{'
)

Related

Get an XML from WEB with a SQL DB2 on Iseries

I have to download the XML generated in this page:
https://www.backend-rates.ezv.admin.ch/api/xmldaily?d=20210923&locale=it
The only parameter is the date in YYYYMMDD format.
I know there are some SQL function to do this, but I don't know how to approce the problem.
EDIT:
I try this:
SELECT * FROM XMLTABLE(
XMLNAMESPACES (DEFAULT 'https://www.backend-rates.ezv.admin.ch/xmldaily',
'https://www.backend-rates.ezv.admin.ch/api/xmldaily?d=20210922&locale=it' AS "doc" ) ,
'doc/wechselkurse/devise' PASSING XMLPARSE
( DOCUMENT SYSTOOLS.HTTPGETBLOB
('https://www.backend-rates.ezv.admin.ch/dailyrates.xsd'
, ''))
COLUMNS
code Char(3) PATH 'code',
waehrung char(10) PATH 'waehrung' ,
kurs decfloat PATH 'kurz'
)
where code = 'USD'
But I obtain an empty result, can you help me find the error?
Multiple problems, listed below the queries because they kill formatting when not below
SELECT * from
XMLTABLE(
XMLNAMESPACES (DEFAULT 'https://www.backend-rates.ezv.admin.ch/xmldaily'),
'$doc/wechselkurse/devise'
PASSING XMLPARSE
(DOCUMENT SYSTOOLS.HTTPGETCLOB('https://www.backend-rates.ezv.admin.ch/api/xmldaily?d=20210922&locale=it', '')) as "doc"
COLUMNS
code Char(3) PATH '#code',
waehrung char(10) PATH 'waehrung' ,
kurs decfloat PATH 'kurs'
)
where code = 'usd'
You don't need to add your document to namespaces since it's not a namesspace
What you download and parse is not the document but the schema that can validate it
You have to give a name to your document in the xpath expression, that's the use of as 'doc' (and not '$doc' like in my previous answer)
You can refer to that name as $doc in the xpath expression
code is an attribute, you can get it's value using #code
code values are lowercase

PG::InvalidParameterValue: ERROR: cannot extract element from a scalar

I'm fetching data from the JSON column by using the following query.
SELECT id FROM ( SELECT id,JSON_ARRAY_ELEMENTS(shipment_lot::json) AS js2 FROM file_table WHERE ('shipment_lot') = ('shipment_lot') ) q WHERE js2->> 'invoice_number' LIKE ('%" abc1123"%')
My Postgresql version is 9.3
Saved data in JSON column:
[{ "id"=>2981, "lot_number"=>1, "activate"=>true, "invoice_number"=>"abc1123", "price"=>378.0}]
However, I'm getting this error:
ActiveRecord::StatementInvalid (PG::InvalidParameterValue: ERROR: cannot extract element from a scalar:
SELECT id FROM
( SELECT id,JSON_ARRAY_ELEMENTS(shipment_lot::json)
AS js2 FROM file_heaps
WHERE ('shipment_lot') = ('shipment_lot') ) q
WHERE js2->> 'invoice_number' LIKE ('%abc1123%'))
How I can solve this issue.
Your issue is that you have improper JSON stored
If you try running your example data on postgres it will not run
SELECT ('[{ "id"=>2981, "lot_number"=>1, "activate"=>true, "invoice_number"=>"abc1123", "price"=>378.0}]')::json
This is the JSON formatted correctly:
SELECT ('[{ "id":2981, "lot_number":1, "activate":true, "invoice_number":"abc1123", "price":378.0}]')::json

SQL Server 2017 Selecting JSON embedded within a JSON field

In SQL Server 2017, I'd like to "SELECT" a JSON object embedded within another as a string so we can store/process them later.
eg JSON:
[
{"key1":"value1",
"level2_Obj":{"key2":"value12"}
},
{"key1":"value2",
"level2_Obj":{"key22":"value22"}
},
]
From above JSON, I'd like to SELECT whole of the level2Obj JSON object, see below for what I'd like to see the "selection" result.
value1 |{"key2" :"value12"}
value2 |{"key22":"value22"}
I tried below with no luck:
SELECT * FROM
OPENJSON(#json,'$."data1"')
WITH(
[key1] nvarchar(50),
[embedded_json] nvarchar(max) '$."level2Obj"'
) AS DAP
Can some one please help how I select the contents of the 2nd level JSON object as a string?
The idea is to Write 1st level JSON properties into individual cells and rest of JSON levels into a single column of type nvarchar(max) (i.e whole of sub-level JSON object into a single column as a string for further processing in later stages).
Good day,
Firstly, Your JSON text is not properly formatted. There is extra comma after the last object in the array. I will remove this extra comma for the sake of the answer, but if this is the format you have then first step will be to clear the text and make sure that is is well formatted.
Please check if this solve your needs:
declare #json nvarchar(MAX) = '
[
{
"key1":"value1",
"level2_Obj":{"key2":"value12"}
}
,
{
"key1":"value2",
"level2_Obj":{"key22":"value22"}
}
]
'
SELECT JSON_VALUE (t1.[value], '$."key1"'), JSON_QUERY (t1.[value], '$."level2_Obj"')
FROM OPENJSON(#json,'$') t1

Get SQL Server column names with values

I am trying to create a query that allows me to have the column name next to its column values that it finds.
As an example:
SELECT
*
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = 'saverTbl'
The above returns all of the column names in that table like this:
id, Link_userTblID, type, environment, vendor, theGUID, theGUID, etc etc...
Now what I need is to get the output from the table name next to the value. This is my query to just get my values from the table:
SELECT
*
FROM
saverTbl
WHERE
LINK_userTblID = #val1
The above returns the row that matches the LINK_userTblID like so:
32, 1, 'Blah', 'something', 'Adobe', 546656156-45332-54616516-4515, etc etc..
Now putting that all together (which is what this question is all about):
id: 32,
LINK_userTblID: 1,
type: Blah,
environment: something,
vendor: Adobe,
theGUID: 546656156-45332-54616516-4515,
etc etc.....
Pretty much needing the output in a json format but the column name matching up with the columns value.
Try this:
SELECT * FROM saverTbl
WHERE LINK_userTblID = #val1
FOR JSON PATH
Assuming, this is meant for one single row you can try this:
WITH cte AS
(
SELECT
(SELECT TOP 1 * FROM sys.objects FOR XML PATH('row'),TYPE) AS TheXml
)
SELECT TheElement.value('local-name(.)','nvarchar(max)')
+ ': '
+ TheElement.value('text()[1]','nvarchar(max)') AS YourOutput
FROM cte
CROSS APPLY TheXml.nodes('/row/*') AS A(TheElement);
The result:
YourOutput
---------------
name: sysrscols
object_id: 3
schema_id: 4
parent_object_id: 0
type: S
type_desc: SYSTEM_TABLE
create_date: 2012-02-10T20:15:58.693
modify_date: 2012-02-10T20:15:58.700
is_ms_shipped: 1
is_published: 0
is_schema_published: 0
XML in connection with XQuery and XPath is a very mighty toolset to solve rather generic problems. The cte builds an XML which looks like this:
<row>
<name>sysrscols</name>
<object_id>3</object_id>
<schema_id>4</schema_id>
<parent_object_id>0</parent_object_id>
<type>S </type>
<type_desc>SYSTEM_TABLE</type_desc>
<create_date>2012-02-10T20:15:58.693</create_date>
<modify_date>2012-02-10T20:15:58.700</modify_date>
<is_ms_shipped>1</is_ms_shipped>
<is_published>0</is_published>
<is_schema_published>0</is_schema_published>
</row>
The call to /row/* retrieves all nodes below <row> as derived table. The rest is rather easy XQuery.

Using Fields[0].Value to get XML from FOR XML RAW, ELEMENTS query is messed up

I have a query that uses FOR XML RAW, ELEMENTS to return a SELECT query as a structured XML document. However, when I get the result using a TSQLDataSet by using Fields[0].Value, the result is different from what I see when I run the query in SQL Server Management Studio.
What I see in the result from the TSQLDataSet:
੄customerIdфname၄governmentNumberไdebtorAddress1ไdebtorAddress2ไdebtorAddress3ไdebtorAddress4ࡄpostCodeୄcontactNameՄphonë́faxൄcustomerSinceՄtermsلactiveไcurrentBalanceلDebtorခŁ䄁ഃӤ
What I see in the result in SSMS:
<Debtor>
<customerId>C0E449E5B2C </customerId>
<name>New Customer 2 </name>
<governmentNumber> </governmentNumber>
<debtorAddress1>Address Line 1 </debtorAddress1>
<debtorAddress4>Address Line 4 </debtorAddress4>
<postCode>1234 </postCode>
<phone>1234567890 </phone>
<fax>1234567890 </fax>
<customerSince>2013-06-10T18:16:06.213</customerSince>
<terms>M </terms>
<active>true</active>
<currentBalance>0.0000</currentBalance>
</Debtor>
Is there a particular way it should be executed to get the right result?
AFAIK this is a DbExpress limitation. I know how overcome this, but using ADO (the returned data must be requested using a special parametrized object and a set of ADO streams). However you can use a workaround converting the XML data to a string in the server side sorrounding the sentence with a select (subquery) or just using a simple CAST statement.
For example if you sentence is like so
SELECT Foo, Bar FROM FooTable FOR XML RAW, ELEMENTS
you can rewrite to
SELECT (SELECT Foo, Bar FROM FooTable FOR XML RAW, ELEMENTS)
or you can rewrite to (use a CAST VARCHAR or NVARCHAR)
SELECT CAST( (SELECT Foo, Bar FROM FooTable FOR XML RAW, ELEMENTS) AS VARCHAR(MAX))
and finally
Retrieve the result like this
SQLDataSet1.Fields[0].AsString