How to add data from table to string - sql

Have table #tbl with INT data :
ID
1
2
3
4
5
want select this id-s and set to declare #myStr nvarchar(max) with " | "
It must be like : 1|2|3|4|5|
how to do it ?

Use following Query:
declare #myStr nvarchar(max)
set #myStr=(SELECT STUFF((
SELECT '|' + CONVERT(VARCHAR,ID)
FROM #tbl
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, ''))
SELECT #myStr

Related

Extract all records from a JSON column, using JSON type

I have a couple tables (see reproducible code at the bottom):
tbl1_have
id json_col
1 {"a_i":"a","a_j":1}
1 {"a_i":"b","a_j":2}
2 {"a_i":"c","a_j":3}
2 {"a_i":"d","a_j":4}
tbl2_have
id json_col
1 [{"a_i":"a","a_j":1},{"a_i":"b","a_j":2}]
2 [{"a_i":"c","a_j":3},{"a_i":"d","a_j":4}]
I wish to extract all json columns without providing explicit data type conversion for each columns since in my use case the names and amounts of nested attributes vary.
The expected output is the same for both cases:
tbl_want
id a_i a_j
1 a 1
1 b 2
2 c 3
2 d 4
with a_i and a_j correctly stored as a character and numeric column, which mean I'd like to map json types to SQL types (say INT and VARCHAR() here) automatically.
The following gets me half way for both tables:
SELECT id, a_i, a_j FROM tbl2_have CROSS APPLY OPENJSON(json_col)
WITH(a_i VARCHAR(100), a_j INT)
id a_i a_j
1 1 a 1
2 1 b 2
3 2 c 3
4 2 d 4
How can I work around mentioning the types explicitly in with() ?
reproducible code :
CREATE TABLE tbl1_have (id INT, json_col VARCHAR(100))
INSERT INTO tbl1_have VALUES
(1, '{"a_i":"a","a_j":1}'),
(1, '{"a_i":"b","a_j":2}'),
(2, '{"a_i":"c","a_j":3}'),
(2, '{"a_i":"d","a_j":4}')
CREATE TABLE tbl2_have (id INT, json_col VARCHAR(100))
INSERT INTO tbl2_have VALUES
(1, '[{"a_i":"a","a_j":1},{"a_i":"b","a_j":2}]'),
(2, '[{"a_i":"c","a_j":3},{"a_i":"d","a_j":4}]')
SELECT id, a_i, a_j FROM tbl1_have CROSS APPLY OPENJSON(json_col)
WITH(a_i VARCHAR(100), a_j INT)
SELECT id, a_i, a_j FROM tbl2_have CROSS APPLY OPENJSON(json_col)
WITH(a_i VARCHAR(100), a_j INT)
I am assuming that you don't know the name and type of keys in advance. You need to use dynamic SQL.
You first need to use OPENJSON without the WITH clause on the {objects} like so:
select string_agg(quotename(k) + case t
when 0 then ' nchar(1)' -- javascript null
when 1 then ' nvarchar(max)' -- javascript string
when 2 then ' float' -- javascript number
when 3 then ' bit' -- javascript boolean
else ' nvarchar(max) as json' -- javascript array or object
end, ', ') within group (order by k)
from (
select j2.[key], max(j2.[type])
from test
cross apply openjson(case when json_col like '{%}' then '[' + json_col + ']' else json_col end) as j1
cross apply openjson(j1.value) as j2
group by j2.[key]
) as kt(k, t)
The inner query gives you the name and type of all the keys across all json values in the table. The outer query builds the WITH clause for dynamic SQL.
The rest is relatively straight forward, use the generated clause in your dynamic SQL. Here is the complete example:
declare #table_name nvarchar(100) = 'test';
declare #with_clause nvarchar(100);
declare #query1 nvarchar(999) = N'select #with_clause_temp = string_agg(quotename(k) + case t
when 0 then '' nchar(1)''
when 1 then '' nvarchar(max)''
when 2 then '' float''
when 3 then '' bit''
else '' nvarchar(max) as json''
end, '', '') within group (order by k)
from (
select j2.[key], max(j2.[type])
from ' + quotename(#table_name) + '
cross apply openjson(case when json_col like ''{%}'' then ''['' + json_col + '']'' else json_col end) as j1
cross apply openjson(j1.value) as j2
group by j2.[key]
) as kt(k, t)';
exec sp_executesql #query1, N'#with_clause_temp nvarchar(100) out', #with_clause out;
declare #query2 nvarchar(999) = N'select id, j.*
from ' + quotename(#table_name) + '
cross apply openjson(json_col)
with (' + #with_clause + ') as j';
exec sp_executesql #query2;
Demo on db<>fiddle
I have found a solution that maybe works for your use case. I am no SQL-expert by any means, and i did not manage to automatically detect the datatypes of the dynamic columns. But i found a solution for your two examples.
First i tried to get all column names dynamically from the json_col. I found an answer on stackoverflow and got this piece of code:
STUFF(
(
SELECT DISTINCT ', '+QUOTENAME(columnname) FROM #tmpTbl FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'), 1, 1, '');
This will output all column names as a string separated by commas, in your example: ' [a_i], [a_j]'. This can then be used to dynamically SELECT columns.
As already mentioned above, i was not able to write a datatype detection algorithm. I just hardcoded the columns to have nvarchar(100) as datatype.
To dynamically get the column-names with the corresponding datatype (hardcoded as nvarchar(100)) i used a slightly modified version of above query:
STUFF(
(
SELECT DISTINCT ', '+QUOTENAME(columnname)+' nvarchar(100)' FROM #tmpTbl FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'), 1, 1, '');
Then i just used them in the WITH-CLAUSE.
Full version for the table tbl1_have
DECLARE #cols NVARCHAR(MAX), #colsWithType NVARCHAR(MAX), #query NVARCHAR(MAX);
DROP TABLE IF EXISTS #tmpTbl
SELECT outerTable.[id] AS columnid, innerTable.[key] AS columnname, innerTable.[value] AS columnvalue
INTO #tmpTbl
FROM tbl1_have outerTable CROSS APPLY OPENJSON(json_col) AS innerTable
SELECT * FROM #tmpTbl
SET #cols = STUFF(
(
SELECT DISTINCT ', '+QUOTENAME(columnname) FROM #tmpTbl FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'), 1, 1, '');
SET #colsWithType = STUFF(
(
SELECT DISTINCT ', '+QUOTENAME(columnname)+' nvarchar(100)' FROM #tmpTbl FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'), 1, 1, '');
SET #query = N'SELECT id, '+#cols+' FROM tbl1_have CROSS APPLY OPENJSON(json_col)
WITH('+#colsWithType+')';
exec sp_executesql #query
Full Version for the table tbl2_have:
DECLARE #cols NVARCHAR(MAX), #colsWithType NVARCHAR(MAX), #query NVARCHAR(MAX);
DROP TABLE IF EXISTS #tmpTbl
DROP TABLE IF EXISTS #tmpTbl2
SELECT *
INTO #tmpTbl
FROM tbl2_have CROSS APPLY OPENJSON(json_col)
SELECT outerTable.[id] AS columnid, innerTable.[key] AS columnname, innerTable.[value] AS columnvalue
INTO #tmpTbl2
FROM #tmpTbl outerTable CROSS APPLY OPENJSON([value]) AS innerTable
SELECT * FROM #tmpTbl
SELECT * FROM #tmpTbl2
SET #cols = STUFF(
(
SELECT DISTINCT ', '+QUOTENAME(columnname) FROM #tmpTbl2 FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'), 1, 1, '');
SET #colsWithType = STUFF(
(
SELECT DISTINCT ', '+QUOTENAME(columnname)+' nvarchar(100)' FROM #tmpTbl2 FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'), 1, 1, '');
SET #query = N'SELECT id, '+#cols+' FROM tbl2_have CROSS APPLY OPENJSON(json_col)
WITH('+#colsWithType+')';
exec sp_executesql #query
Would using the Value returned from OPENJSON work? It probably maps to a string data type, however, you do not have to know the type upfront. The official doc of the OPENJSON rowset function indicates that it returns a Key:Value pair as well as a Type for each parse. The Type value may be useful, however, it determines the datatype while parsing. I bet that Value is always a string type, as it would have to be.
;WITH X AS
(
SELECT id, a_i=J.[Key], a_j=J.[Value] FROM #tbl2_have CROSS APPLY OPENJSON(json_col) J
)
SELECT
id,
a_i=MAX(CASE WHEN J.[Key]='a_i' THEN J.[Value] ELSE NULL END),
a_j=MAX(CASE WHEN J.[Key]='a_j' THEN J.[Value] ELSE NULL END)
FROM X CROSS APPLY OPENJSON(X.a_j) J
GROUP BY
id,a_i,a_j

Display Alias name for each column in dynamic query SQL Server

I have below table.
create table demo(id int, dataval varchar(50))
insert into demo
select 1, 'val'
union
select 2, 'val1'
union
select 3, 'val3'
I am trying to get the list of values of dataval column surrounded with max() in a variable using below query
DECLARE #maxcols AS NVARCHAR(MAX)
SELECT #maxcols = STUFF((SELECT DISTINCT ',' + 'MAX('+QUOTENAME([dataval] ) + ') AS [val]'
FROM demo
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
SELECT #maxcols AS val
I am getting below values.
max([val])as [val],max([val1])as [val],max([val3])as [val]
Here the alias name coming as static value [val]. I need the alias name displayed as column values.
Expected output:
max([val])as [val1],max([val1])as [val2],max([val3])as [val3]
Could someone help on this?
You can use row_Number as below:
DECLARE
#maxcols AS NVARCHAR(MAX)
select #maxcols = STUFF((SELECT distinct ',' + 'max('+QUOTENAME([dataval] )+')as [val'+ convert(varchar(10), Row_Number() over (order by (SELECT NULL))) + ']'
from demo
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #maxcols as val
Output as below:
+---------------------------------------------------------------+
| val |
+---------------------------------------------------------------+
| max([val])as [val1],max([val1])as [val2],max([val3])as [val3] |
+---------------------------------------------------------------+

How to create a SQL Server Pivot query?

I want to create sql query result. I want to dynamically create because of inventory locations are one or more. (Example.. CTE)
Item_id Location Qty
--------------------------
1 a 1
2 b 2
3 c 3
3 a 1
2 c 2
1 b 3
Result is....
Item_id a_Location_Qty b_Location_Qty c_Location_Qty
-------------------------------------------------------
1 1 3 0
2 0 2 2
3 1 0 3
Please try below code
Create Table #Stack10072017040904(Item_id varchar(100),Location varchar(100),Qty int)
insert into #Stack10072017040904 select '1','a','1'
insert into #Stack10072017040904 select '2','b','2'
insert into #Stack10072017040904 select '3','c','3'
insert into #Stack10072017040904 select '3','a','1'
insert into #Stack10072017040904 select '2','c','2'
insert into #Stack10072017040904 select '1','b','3'
select Item_id,Isnull(a,0) a_Location_Qty
,isnull(b,0)b_Location_Qty
,isnull(c,0)c_Location_Qty
from #Stack10072017040904
pivot
(Sum(Qty) for Location in ([a],[b],c) )pvt
drop table #Stack10072017040904
Try this Dynamic Sql
Declare
#Sql nvarchar(max),
#dynamicCol nvarchar(max),
#dynamicCol2 nvarchar(max)
--Create columns Dynamically
SELECT #dynamicCol=STUFF((SELECT DISTINCT ', '+ QUOTENAME(Location )
From #Stack10072017040904 For XML PATH ('')),1,1,'')
SELECT #dynamicCol2=STUFF((SELECT DISTINCT ', '+ 'ISNULL ('+ QUOTENAME(Location )+ ','+'''0'''+')' +' AS '+Location+'_Location_Qty'
From #Stack10072017040904 For XML PATH ('')),1,1,'')
SET #Sql='
SELECT [Item_id] ,'+ #dynamicCol2 +' From
(
SELECT * From
#Stack10072017040904
)AS Src
PIVOT
(
MAX([Qty]) For [Location] IN ('+#dynamicCol+')
)
AS Pvt'
PRINT #Sql
EXEC(#Sql)
Result
Item_id a_Location_Qty b_Location_Qty c_Location_Qty
-------------------------------------------------------
1 1 3 0
2 0 2 2
3 1 0 3
Build columns dynamically and use a dynamic PIVOT:
Create Table #Test(Item_id varchar(100),Location varchar(100),Qty int)
insert into #Test values( '1','a','1')
insert into #Test values( '2','b','2')
insert into #Test values( '3','c','3')
insert into #Test values( '3','a','1')
insert into #Test values( '2','c','2')
insert into #Test values( '1','b','3')
DECLARE #cols1 AS NVARCHAR(MAX), #cols2 AS NVARCHAR(MAX), #query AS NVARCHAR(MAX);
SET #cols1 = STUFF((SELECT distinct ', isnull(' + quotename(s.Location) + ', 0) as ' + quotename(s.Location)
FROM #Test s
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #cols2 = STUFF((SELECT distinct ',' + quotename(s.Location)
FROM #Test s
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Item_id, ' + #cols1 + ' from
(
select Item_id
, Location
, Qty
from #Test
) x
pivot
(
max(qty)
for Location in (' + #cols2 + ')
) p '
execute(#query)
drop table #Test

How to pivot rows into colums dynamically SQL Server

I have a request which returns something like this:
--------------------------
Tool | Week | Value
--------------------------
Test | 20 | 3
Sense | 20 | 2
Test | 19 | 2
And I want my input to look like this:
-------------------------
Tool | W20 | W19
-------------------------
Test | 3 | 2
Sense | 2 | null
Basically, for every week I need to have a new column. The number of week and of tools is dynamic.
I have tried many things but nothing worked. Anybody have a solution ?
Try this
CREATE table #tst (
Tool varchar(50), [Week] int, Value int
)
insert #tst
values
('Test', 20, 3),
('Sense', 20,2),
('Test', 19, 2)
Here is the Dynamic Query:
DECLARE #col nvarchar(max), #query NVARCHAR(MAX)
SELECT #col = STUFF((SELECT DISTINCT ',' + QUOTENAME('W' + CAST([Week] as VARCHAR))
from #tst
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query = '
SELECT *
FROM (
SELECT Tool,
Value,
''W'' + CAST([Week] as VARCHAR) AS WeekNo
FROM #tst
) t
PIVOT
(
MAX(t.Value)
FOR WeekNo IN (' + #col + ')
) pv
ORDER by Tool'
EXEC (#query)
Result
Tool W20 W19
=================
Sense 2 NULL
Test 3 2
IF OBJECT_ID('tempdb..#temp') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp
( Tool varchar(5), Week int, Value int)
;
INSERT INTO #temp
( Tool , Week , Value )
VALUES
('Test', 20, 3),
('Sense', 20, 2),
('Test', 19, 2)
;
DECLARE #statement NVARCHAR(max)
,#columns NVARCHAR(max),
#col NVARCHAR(max)
SELECT #columns = ISNULL(#columns + ', ', '') + N'[' +'w'+ tbl.[Week] + ']'
FROM (
SELECT DISTINCT CAST([Week] AS VARCHAR)[Week]
FROM #temp
) AS tbl
SELECT #statement = 'SELECT *
FROM
(
SELECT
Tool , ''w''+ CAST(Week AS VARCHAR) week , Value
FROM
#Temp
) src
PIVOT(MAX(Value)for Week in (' + #columns + ')) as pvt
'
EXEC sp_executesql #statement = #statement
This is how I would do it ... If I understood your question correctly
if object_id('tempdb..#InputTool') is not null drop table #InputTool
create table #InputTool (Tool nvarchar(10), [20] int, [19] int)
insert into #InputTool (Tool, [20], [19])
values
('Test', 3, 2),
('Sense', 2, null)
declare #cols nvarchar(max)
select #cols = STUFF((SELECT ',' + QUOTENAME(name)
from tempdb.sys.columns
where object_id = object_id('tempdb..#InputTool')
and Column_id > 1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
declare #sqlquery nvarchar(max) =
'select Tool, Weeks, Value from (
select * from #InputTool
) as it
UNPIVOT
(
Value FOR Weeks IN (' + #cols + ')
) AS Weeks
order by Weeks desc'
execute (#sqlquery);
Give it a shot and let me know if it worked

output of stored procedure should come in single line

Following is my Query which given output in multiple Lines I want in a single line
create table #temptable
(userid int,UserName nvarchar(50),WardId bigint,ZoneId bigint,WardName nvarchar(255))
insert into #temptable
exec GetWardWiseHierarchyUser #wardid --354
SELECT distinct WardId FROM #temptable
declare #StringWardId nvarchar(max)
select #StringWardId=(select stuff((select ',' + cast(wardId as nvarchar(50)) from #temptable
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1,'' ))
This SP giving Following Output
WardId
10054
10056
10057
10058
But I want this output like
WardId
10054,10056,10057,10058
Please Help me to solve this problem
COALESCE only replace null to ' '
DECLARE #WardId VARCHAR(8000)
SELECT #WardId = COALESCE(#WardId + ', ', '') + WardId
FROM tbl