FOR JSON - How can I create JSON array output without keys? - json

I'm playing around with the FOR JSON features in SQL Server 2019, and I'm struggling with how to use that feature to create a JSON list without keys... so like just a straight-up list of values.
For example, say I have this SQL:
declare #years table (year int)
insert into #years values (2022),(2021),(2020)
SELECT year
FROM #years
FOR JSON AUTO
This creates output like so:
[{"year":2022},{"year":2021},{"year":2020}]
But how would I get it to create output like THIS instead:
[2022,2021,2020]
And I'm looking to do this without messy nested string replaces... but maybe that's the only way? Thanks a lot for any help!

Please try the following solution.
It will work starting from SQL Server 2017 onwards.
SQL
DECLARE #tbl TABLE ([year] int);
INSERT INTO #tbl VALUES (2022),(2021),(2020);
SELECT json = QUOTENAME(STRING_AGG([year], ','))
FROM #tbl;
Output
json
[2022,2021,2020]

Related

How to reuse JSON arguments within PostgreSQL stored procedure

I am using a stored procedure to INSERT into and UPDATE a number of tables. Some of the data is derived from a JSON parameter.
Although I have successfully used json_to_recordset() to extract named data from the JSON parameter, I cannot figure how to use it in an UPDATE statement. Also, I need to use some items of data from the JSON parameter a number of times.
Q: Is there a way to use json_to_recordset() to extract named data to a temporary table to allow me to reuse the data items throughout my stored procedure? Maybe I should SELECT INTO variables within the stored procedure?
Q: Failing that can anyone please provide a simple example of how to update a table using data returned from json_to_recordset(). I must also include data not from the JSON parameter such as now()::timestamp(0).
This is how I have used json_to_recordset() so far:
INSERT INTO myRealTable (
rec_timestamp,
rec_data1,
rec_data2
)
SELECT
now()::timestamp(0),
x.data1,
x.data2
FROM json_to_recordset(json_parameter) x
(
json_data1 int,
json_data2 boolean
);
Thank you.

How to Map JSON data from a REST API to Azure SQL using Data Factory

I have a new pipeline in azure data factory.
I created the dataset, one from the rest api (a public one):
https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MSFT&apikey=demo
and then I created an azure sql table with columns shown in the screenshot
The problem, is that I dont know how to do the mapping, as this is a complex JSON object, I am limited with the Mapping Designer:
How do I map the date?
I tend to use an ELT approach for these, calling the REST API with a Web task and storing the JSON in a SQL table and then shredding the JSON using SQL functions like OPENJSON.
Example pipeline:
The key to getting this approach to work is the expression on the stored procedure parameter. This takes the whole JSON output from the Web task and passes it in to the proc. This is a simple logging proc which inserts the record into a logging table:
#string(activity('Web1').output)
I log to a table and then shred the JSON or you could use OPENJSON directly on the stored proc parameter, eg
--INSERT INTO ...
SELECT
CAST( [key] AS DATE ) AS timeSeriesDate,
JSON_VALUE ( x.[value], '$."1. open"' ) AS [open],
JSON_VALUE ( x.[value], '$."2. high"' ) AS [high],
JSON_VALUE ( x.[value], '$."3. low"' ) AS [low],
JSON_VALUE ( x.[value], '$."4. close"' ) AS [close],
JSON_VALUE ( x.[value], '$."5. volume"' ) AS [volume]
FROM dbo.myLog
CROSS APPLY OPENJSON(logDetails , '$."Time Series (Daily)"' ) x
--WHERE logId = 23333;
My results:
Does the data have a structure? If so, you can generate a dummy file, place it in sink and do a one time mapping. If not, you can Lookup on the file, iterate over the content in a For Each Loop Container and insert details on to a SQL table.
E.g.
insert <<your table>>
select '#item().name', '#item().address.city', #item().value
The important thing to remember is to iterate at the correct array. Let me know if it's not clear. Not in front of a system right now, so can't add screenshots.

Parsing TFS 2010 Process Arguments XML with T-SQL and XQuery

I am trying to the get the value of the x:String node (L1.0.0.0) in XML below shown code sample. The XML in the sample is generated by the TFS 2010 when we queue the builds. The XML has two major nodes and Dictionary and x:String and I have tried the query similar to the other stack overflow thread and I have included that under additional research. Any one got any suggestions why my XQuery is not working?
DECLARE #XML XML;
SET #XML = '<Dictionary x:TypeArguments="x:String, x:Object"
xmlns="clr-namespace:System.Collections.Generic;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:String x:Key="GetVersion">L1.0.0.0</x:String>
</Dictionary>'
;WITH XMLNAMESPACES(
'clr-namespace:System.Collections.Generic;assembly=mscorlib' AS a,
'http://schemas.microsoft.com/winfx/2006/xaml' AS x)
SELECT #XML.value('(/Dictionary/x:String)[1]', varchar(100)) AS BuildLabel
Additional Research
Stack Overflow
T-SQL, XQuery Invalid Column
How to work with multiple namespaces
In your query you need to prefix Dictionary with a since clr-namespace:System.Collections.Generic;assembly=mscorlib is the default namespace and Dictionary belongs to that.
;WITH XMLNAMESPACES(
'clr-namespace:System.Collections.Generic;assembly=mscorlib' AS a,
'http://schemas.microsoft.com/winfx/2006/xaml' AS x)
SELECT #XML.value('(/a:Dictionary/x:String)[1]', 'varchar(100)') AS BuildLabel
Or you can specify the namespace as default in the query.
;WITH XMLNAMESPACES('http://schemas.microsoft.com/winfx/2006/xaml' as x,
DEFAULT 'clr-namespace:System.Collections.Generic;assembly=mscorlib')
SELECT #XML.value('(/Dictionary/x:String)[1]', 'varchar(100)') AS BuildLabel

Updating XML column with the new XML using parameterized stored procedure

This is something new for me to try using XML column in SQL server 2008 database. I have seen few posts related to this, but I am able to find it difficult.
Let me put my question in a simplest form.
I have a database table dbo.cXML that has the columns EmailID(nVarchar(128)), ClientID(int) and cycleXML(XML).
My middleware component implements complex business logic and spit out the XML after logic processing.
Now I have a requirement that need the following:
a) A stored procedure with parameters in place to perform a check on above table to see if there is already an XML for a given EmailID and Client ID. If a record exists, use Update query to update entire XML otherwise simply insert the XML.
b) A stored procedure whould be able to send back the complete XML to my middleware component on request.
Can someone please help me understand the pseudo code. Appreciate your help.
Thanks,
Yagya
Not totally sure what you mean by requirement 3b but does this help you???
IF EXISTS (SELECT 1 FROM dbo.cXML WHERE EmailID = #YourEmailID AND ClientID = #YourClientID)
BEGIN
UPDATE dbo.cXML
SET cycleXML = #YourXML
WHERE EmailID = #YourEmailID AND ClientID = #YourClientID
END
ELSE BEGIN
INSERT INTO dbo.cXML (EmailID, ClientID, cycleXML)
SELECT #YourEmailID, #YourClientID, #YourXML
END

Unable to retrieve column information: No colum information was returned by the sql command

I am using Microsoft sql server 2008, I tried all the 3 solutions, but every time I get the same error
Error at Data Flow Task[OLEDB source[449]]:No colum information was returned by the sql command
I am using the following batch of sql statments to retrieve the server level configuration of all servers in my company. The table variable #tb1_SvrStng has 83 columns and it is populated using different resources.
So I summarize the sql script. I cannot use it as stored procedure because this script is going to run against 14 servers (once for each server). So if I store the procedure on one server, other server cannot execute that procedure in its context.
I will highly appreciate your help. I am not using any temporary table in my script.
declare #tb1_SvrStng table
(
srvProp_MachineName varchar(50),
srvProp_BldClrVer varchar(50),
srvProp_Collation varchar(50),
srvProp_CNPNB varchar(100),
...
xpmsver_ProdVer varchar(50),
..... .
syscnfg_UsrCon_cnfgVal int,
.....
);
insert into #tb1_SvrStng
(
srvProp_BldClrVer,
srvProp_Collation,
srvProp_CNPNB , ........
........ .
)
select convert(varchar, serverproperty('BuildClrVer')),
convert(varchar, serverproperty('Collation'))
........
.......
declare #temp_msver1 table
(
id int, name varchar(100),
...........
);
insert into #temp_msver1 exec xp_msver
Update #tb1_SvrStng
set xpmsver_ProdVer =
(
select value from #temp_msver1 where name = 'ProductVersion'
),
xpmsver_Platform =
(
select value from #temp_msver1 where name = 'Platform'
),
.....
......
select
srvProp_SerName as srvProp_SerName,
getdate() as reportDateTime,
srvProp_BldClrVer as srvProp_BldClrVer,
srvProp_Collation as srvProp_Collation,
.....
.....
from #tb1_SvrStng
From what i can gather from your code and question is that the query cannot be processed outside runtime, because you're doing something dynamic to it, or that it won't process it since it's doing something funky.
One trick to this would be to use the Source component in the data flow task to something "dummy" - which you can fake with a query like this
SELECT
CONVERT(DATATYPE,NULL) AS srvProp_SerName,
CONVERT(DATETIME,NULL) AS reportDateTime,
CONVERT(DATATYPE,NULL) AS srvProp_BldClrVer,
CONVERT(DATATYPE,NULL) AS srvProp_Collation
This way the source component should be able to read the metadata. You can then put your proper query (as long as it's within the limits of the length of the query text) into a variable, and then assign this as an expression to the source component.
At runtime it will then use the expression query - and hopefully don't mind too much the metadata issue.
This may or may not work but it should be worth a try since it won't take long to confirm.