Related
I'd like to use FOR JSON to build a data payload for an HTTP Post call. My Source table can be recreated with this snippet:
drop table if exists #jsonData;
drop table if exists #jsonColumns;
select
'carat' [column]
into #jsonColumns
union
select 'cut' union
select 'color' union
select 'clarity' union
select 'depth' union
select 'table' union
select 'x' union
select 'y' union
select 'z'
select
0.23 carat
,'Ideal' cut
,'E' color
,'SI2' clarity
,61.5 depth
,55.0 [table]
,3.95 x
,3.98 y
,2.43 z
into #jsonData
union
select 0.21,'Premium','E','SI1',59.8,61.0,3.89,3.84,2.31 union
select 0.29,'Premium','I','VS2',62.4,58.0,4.2,4.23,2.63 union
select 0.31,'Good','J','SI2',63.3,58.0,4.34,4.35,2.75
;
The data needs to be formatted as follows:
{
"columns":["carat","cut","color","clarity","depth","table","x","y","z"],
"data":[
[0.23,"Ideal","E","SI2",61.5,55.0,3.95,3.98,2.43],
[0.21,"Premium","E","SI1",59.8,61.0,3.89,3.84,2.31],
[0.23,"Good","E","VS1",56.9,65.0,4.05,4.07,2.31],
[0.29,"Premium","I","VS2",62.4,58.0,4.2,4.23,2.63],
[0.31,"Good","J","SI2",63.3,58.0,4.34,4.35,2.75]
]
}
My attempts thus far is as follows:
select
(select * from #jsonColumns for json path) as [columns],
(select * from #jsonData for json path) as [data]
for json path, without_array_wrapper
However this returns arrays of objects rather than values, like so:
{
"columns":[
{"column":"carat"},
{"column":"clarity"},
{"column":"color"},
{"column":"cut"},
{"column":"depth"},
{"column":"table"},
{"column":"x"},
{"column":"y"},
{"column":"z"}
]...
}
How can I limit the arrays to only showing the values?
Honestly, this seems like it's going to be easier with string aggregation rather than using the JSON functionality.
Because you're using using SQL Server 2016, you don't have access to STRING_AGG or CONCAT_WS, so the code is a lot longer. You have to make use of FOR XML PATH and STUFF instead and insert all the separators manually (why there's so many ',' in the CONCAT expression). This results in the below:
DECLARE #CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SELECT N'{' + #CRLF +
N' "columns":[' + STUFF((SELECT ',' + QUOTENAME(c.[name],'"')
FROM tempdb.sys.columns c
JOIN tempdb.sys.tables t ON c.object_id = t.object_id
WHERE t.[name] LIKE N'#jsonData%' --Like isn't needed if not a temporary table. Use the literal name.
ORDER BY c.column_id ASC
FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,1,N'') + N'],' + #CRLF +
N' "data":[' + #CRLF +
STUFF((SELECT N',' + #CRLF +
N' ' + CONCAT('[',JD.carat,',',QUOTENAME(JD.cut,'"'),',',QUOTENAME(JD.color,'"'),',',QUOTENAME(JD.clarity,'"'),',',JD.depth,',',JD.[table],',',JD.x,',',JD.y,',',JD.z,']')
FROM #jsonData JD
ORDER BY JD.carat ASC
FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,3,N'') + #CRLF +
N' ]' + #CRLF +
N'}';
DB<>Fiddle
I have a table with fields: country_code, short_name, currency_unit, a2010, a2011, a2012, a2013, a2014, a2015. a2010-a2015 fields are type of double.
How do I make a query which orders the results by average of fields a2010-a2015, keeping in mind that these fields might have NULL value?
I tried this code and it did not work (returns a mistake, which tells there is something wrong in ORDER BY part. mistake was saying something about coumn names and GROUP BY). The logic is: ORDER BY ((A)/(B)) where A - sum of not NULL fields and B - count of not NULL fields.
Any ideas?
(if important, the code is going to be used in BigInsights environment)
SELECT country_code, short_name, currency_unit, a2010, a2011, a2012,
a2013, a2014, a2015
FROM my_schema.my_table
WHERE Indicator_Code = 'SE.PRM.TENR'
ORDER BY
(
(
Coalesce(a2010,0) + Coalesce(a2011,0) + Coalesce(a2012,0)
+Coalesce(a2013,0) + Coalesce(a2014,0) + Coalesce(a2015,0)
)
/
(
COUNT(Coalesce(a2010)) + COUNT(Coalesce(a2011)) + COUNT(Coalesce(a2012))
+ COUNT(Coalesce(a2013)) + COUNT(Coalesce(a2014)) +
COUNT(Coalesce(a2015))
)
) DESC;
use MySQL ifnull
IFNULL(expression_1,expression_2)
in your query :-
IFNULL(
(
COUNT(Coalesce(a2010)) + COUNT(Coalesce(a2011)) + COUNT(Coalesce(a2012))
+ COUNT(Coalesce(a2013)) + COUNT(Coalesce(a2014)) +
COUNT(Coalesce(a2015))
),
1
)
I have read and tried most of the related topics on this forum, but most of them don't have a lot of feedback.
So I am using SSRS 2008 R2 with Report Builder 3.
I have a simple SP as follows that filters my data using the IN.
But for some reason its not passing the parameters correctly to my sp and only filter's by the first option I select, hope you can assist.
--SP
#Warehouse varchar(max)
AS
BEGIN
SELECT WBal.Warehouse ,WBal.StockCode,((WBal.[Current] - WBal.Bal1)) CMov,((WBal.Bal1 - WBal.Bal2)) P1Mov,((WBal.Bal2 - WBal.Bal3)) P2Mov
,((WBal.Bal3 - WBal.Bal4)) P3Mov,((WBal.Bal4 - WBal.Bal5)) P4Mov,((WBal.Bal5 - WBal.Bal6)) P5Mov,((WBal.Bal6 - WBal.Bal7)) P6Mov
,((WBal.Bal7 - WBal.Bal8)) P7Mov,((WBal.Bal8 - WBal.Bal9)) P8Mov,((WBal.Bal9 - WBal.Bal10)) P9Mov,((WBal.Bal10 - WBal.Bal11)) P10Mov
,((WBal.Bal11 - WBal.Bal12)) P11Mov
FROM
(
SELECT [StockCode]
,[Warehouse]
,(QtyOnHand * UnitCost) [Current]
,(OpenBalCost1 * OpenBalQty1) Bal1
,(OpenBalCost2 * OpenBalQty2) Bal2
,(OpenBalCost3 * OpenBalQty3) Bal3
,(OpenBalCost4 * OpenBalQty4) Bal4
,(OpenBalCost5 * OpenBalQty5) Bal5
,(OpenBalCost6 * OpenBalQty6) Bal6
,(OpenBalCost7 * OpenBalQty7) Bal7
,(OpenBalCost8 * OpenBalQty8) Bal8
,(OpenBalCost9 * OpenBalQty9) Bal9
,(OpenBalCost10 * OpenBalQty10) Bal10
,(OpenBalCost11 * OpenBalQty11) Bal11
,(OpenBalCost12 * OpenBalQty12) Bal12
FROM [SysproCompanyR].[dbo].[InvWarehouse]
Where Warehouse in (SELECT * FROM dba_parseString_udf((#Warehouse), ' '))
) WBal
END
I have the following udf that apparently will split of the string, but im not that good with this so I don't know if my problem perhaps lies with the udf
UDF
ALTER FUNCTION [dbo].[dba_parseString_udf]
(
#stringToParse VARCHAR(8000)
, #delimiter CHAR(1)
)
RETURNS #parsedString TABLE (stringValue VARCHAR(128))
AS
/*********************************************************************************
Name: dba_parseString_udf
Author: Michelle Ufford, http://sqlfool.com
Purpose: This function parses string input using a variable delimiter.
Notes: Two common delimiter values are space (' ') and comma (',')
Date Initials Description
----------------------------------------------------------------------------
2011-05-20 MFU Initial Release
*********************************************************************************
Usage:
SELECT *
FROM dba_parseString_udf(<string>, <delimiter>);
Test Cases:
1. multiple strings separated by space
SELECT * FROM dbo.dba_parseString_udf(' aaa bbb ccc ', ' ');
2. multiple strings separated by comma
SELECT * FROM dbo.dba_parseString_udf(',aaa,bbb,,,ccc,', ',');
*********************************************************************************/
BEGIN
/* Declare variables */
DECLARE #trimmedString VARCHAR(8000);
/* We need to trim our string input in case the user entered extra spaces */
SET #trimmedString = LTRIM(RTRIM(#stringToParse));
/* Let's create a recursive CTE to break down our string for us */
WITH parseCTE (StartPos, EndPos)
AS
(
SELECT 1 AS StartPos
, CHARINDEX(#delimiter, #trimmedString + #delimiter) AS EndPos
UNION ALL
SELECT EndPos + 1 AS StartPos
, CharIndex(#delimiter, #trimmedString + #delimiter , EndPos + 1) AS EndPos
FROM parseCTE
WHERE CHARINDEX(#delimiter, #trimmedString + #delimiter, EndPos + 1) <> 0
)
/* Let's take the results and stick it in a table */
INSERT INTO #parsedString
SELECT SUBSTRING(#trimmedString, StartPos, EndPos - StartPos)
FROM parseCTE
WHERE LEN(LTRIM(RTRIM(SUBSTRING(#trimmedString, StartPos, EndPos - StartPos)))) > 0
OPTION (MaxRecursion 8000);
RETURN;
END
So what im trying to achieve is, I have a sp that populates my values for my parameter as did the setup like follow in ssrs
SELECT DISTINCT (Warehouse)
FROM [SysproCompanyR].[dbo].[InvWarehouse]
And then in my Dataset for my report where I need to apply this looks I have tried various alternatives in the parameter option:
expression
=JOIN(Parameters!Warehouse.Value,",")
When you pass multiple values from SSRS, it sends the values as comma delimited value1,value2,value3....
In you query you are splitting on white string ' '
Where Warehouse in (SELECT * FROM dba_parseString_udf((#Warehouse), ' '))
It should be using comma , instead of the white space ' '
Where Warehouse in (SELECT * FROM dba_parseString_udf((#Warehouse), ','))
I want to simplify the following using dynamic SQL like one could do in Transact SQL.
I want to do something like:
SET #s = replace(field_name, '_complete','')
and use #s instead of replace(field_name, '_complete','')
Please adive if possible and if so how.
My current code:
select distinct
if(instr(replace(field_name, '_complete',''),'_') <= 5
,left(replace(field_name, '_complete','')
,instr(replace(field_name, '_complete',''),'_') - 1
)
,replace(field_name, '_complete','')
) AS form_id ,replace(
if(instr(replace(field_name, '_complete',''),'_') <= 5,
mid(replace(field_name, '_complete',''),
instr(replace(field_name, '_complete',''),'_') + 1,
length(replace(field_name, '_complete','')) - instr(replace(field_name, '_complete',''),'_')
)
,replace(field_name, '_complete','')
),
'_',
' ') as form_name ,field_name from redcap_extract2use where field_name like '%_complete' order by 1;
The above would then be replaced with:
select distinct
if(instr(#s,'_') <= 5 ,left(#s,instr(#s,'_') - 1),#s ) AS form_id
,replace( if(instr(#s,'_') <= 5,
mid(#s,instr(#s,'_') + 1,length(#s) - instr(#s,'_')),#s), '_', ' ') as form_name
,field_name
from redcap_extract2use
where field_name like '%_complete'
order by 1;
and I would have an execute... to run the query
If I'm understanding your question correctly then you would want to use the PREPARE and the EXECUTE statements.
For example:
SET #s = replace(field_name, '_complete','');
PREPARE mystatement FROM
SELECT DISTINCT ...... ;
EXECUTE mystatement;
I have a column in one of my tables, which is TIME format (00:00:00). I am trying to sum the entire column and display it as same (00:00:00).
I have tried using the following but it is not giving me anywhere near the correct answer.It's giving me 22.12:44:00 and manual calcaulation tells me it should be close to 212:something:something
SELECT SEC_TO_TIME( SUM( TIME_TO_SEC( vluchttijd ) ) ) AS totaltime FROM tbl_vluchtgegevens
Any recommendations?
You can try like this:-
SELECT SEC_TO_TIME(SUM(SECOND(vluchttijd ))) AS totaltime FROM tbl_vluchtgegevens;
or try this(althoug this is not a good approach):
SELECT concat(floor(SUM( TIME_TO_SEC( `vluchttijd ` ))/3600),":",floor(SUM( TIME_TO_SEC( `vluchttijd ` ))/60)%60,":",SUM( TIME_TO_SEC( `vluchttijd ` ))%60) AS total_time
FROM tbl_vluchtgegevens;
Edit:-
Try this:-
select cast(sum(datediff(second,0,dt))/3600 as varchar(12)) + ':' +
right('0' + cast(sum(datediff(second,0,dt))/60%60 as varchar(2)),2) +
':' + right('0' + cast(sum(datediff(second,0,dt))%60 as varchar(2)),2)
from TestTable
Working SQL Fidlle
In MySQL, the TIME type is rather limited in range. Moreover many time function do not accept values greater that 23:59:59, making it really usable only to represent the time of the day.
Given your needs, your best bet is probably to write a custom function that will mimic SEC_TO_TIME but allowing much greater range:
CREATE FUNCTION SEC_TO_BIGTIME(sec INT)
RETURNS CHAR(10) DETERMINISTIC
BEGIN
SET #h = sec DIV 3600;
SET #m = sec DIV 60 MOD 60;
SET #s = sec MOD 60;
RETURN CONCAT(
LPAD(#h, 4, '0'),
':',
LPAD(#m, 2, '0'),
':',
LPAD(#s, 2, '0')
);
END;
And here is how to use it:
create table tbl (dt time);
insert tbl values
('09:00:00'), ('01:00:00'), ('07:50:15'), ('12:00:00'),
('08:30:00'), ('00:45:00'), ('12:10:30');
select SEC_TO_BIGTIME(sum(time_to_sec(dt))) from tbl;
Producing:
+--------------------------------------+
| SEC_TO_BIGTIME(SUM(TIME_TO_SEC(DT))) |
+--------------------------------------+
| 0051:15:45 |
+--------------------------------------+
See http://sqlfiddle.com/#!8/aaab8/1
Please note the result is a CHAR(10) in order to overcome TIMEtype limitations. Depending how you plan to use that result, that means that you may have to convert from that string to the appropriate type in your host language.
This worked for me:
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(vluchttijd))) AS totaltime FROM tbl_vluchtgegevens;