Decode Base64 using a column as a variable - sql

Objective:
I would like to Decode a Base64 column from a table using the OPENJSON function and extract the 'a' key from that decoded string as such:
DECLARE #JSON nvarchar(MAX) = 'column name' -- Here i am puting 'column name' because im not sure how to insert a column into a declared variable.
SELECT [Value]
FROM OPENJSON(#JSON)
WHERE [key] = 'a';
Situation:
I have a column ('ProductsBase64') that is Base64 encoded that I would like to decode.
Example of a unique string:
I would like to decode an entire column however
DECLARE #JSON nvarchar(MAX) = N'{"a":1,"b":2,"c":3,"d":4}';
SELECT *
FROM OPENJSON(#JSON)
where type = 2
Results:
key value type
a 1 2
b 2 2
c 3 2
d 4 2

Assuming the original text encoding is compatible with varchar you can use the below (uses XML xs:base64Binary method to do the base 64 decoding, that is then cast to VARCHAR and finally passed as input to OPENJSON)
CREATE TABLE #t
(
ProductsBase64 VARCHAR(max)
)
INSERT INTO #t
VALUES ('eyJhIjoxLCJiIjoyLCJjIjozLCJkIjo0fQ=='); /*{"a":1,"b":2,"c":3,"d":4} */
SELECT ca.*
FROM #t
CROSS APPLY (SELECT *
FROM OPENJSON(
CONVERT (
VARCHAR(MAX),
CAST('' AS XML).value('xs:base64Binary(sql:column("ProductsBase64"))', 'VARBINARY(MAX)')
)
)
WHERE type = 2) ca

Related

unpivot list : data type error in SQL SERVER

I'm trying to UNPIVOT some columns in the table but having trouble with some of the columns as the datatype is different. So I tried to CAST all columns to VARCHAR(255) but it still doesn't work.
It gives error that:
Conversion failed when converting the varchar value '' to data type int
I am not sure how is this error occurring when I am converting to varchar and not to int.
Table1 originally has 4 columns c1 , c2 ,c3,c4
column - Datatype
c1 - tinyint,
c2-tinyint,
c3-tinyint,
c4-nvarchar(255),
SAMPLE DATA:
c1 : 1,
c2:1,
c3:0,
c4:'Profit'
Need to combine multiple columns into one column hence using unpivot
SELECT *
FROM
(select
,CAST([c1] AS varchar(255)) AS[c1]
,CAST([c2] AS varchar(255)) AS[c2]
,CAST([c3] AS varchar(255)) AS[c3]
,CAST([c4] AS varchar(255)) AS[c4]
from table1)a
UNPIVOT ([set] FOR [sets] IN ([c1],[c2],[c3],[c4])
Error : "Conversion failed when converting the varchar value 'profit' to data type int."
Try this one
Select *
From (
Select CAST([c1] AS varchar(255)) AS[c1]
,CAST([c2] AS varchar(255)) AS[c2]
,CAST([c3] AS varchar(255)) AS[c3]
,CAST([c4] AS varchar(255)) AS[c4]
from table1
) A
unpivot ([set] FOR [sets] IN ([c1],[c2],[c3],[c4]) ) unp
Results
set sets
1 c1
1 c2
0 c3
Profit c4
EDIT
Not clear where the error is coming from, but here is a dynamic UNPIVOT without using Dynamic SQL and no need to convert datatypes.
Select B.*
From table1 A
Cross Apply (
Select [Key]
,Value
From OpenJson((Select A.* For JSON Path,Without_Array_Wrapper,INCLUDE_NULL_VALUES ))
) B

How to extract specific text from column

I am using SQL Server 2016 where I am loading JSON Response in one of the nvarchar(max) type column.
Now I want to create a derived column or maybe even a view that will find the particular value in that complete JSON Response and display only that in the new derived column.
Example:
**Complete_JSON_Repsone** --> this is SQL column
{"result":{"banner_image_light":"","country":"USA","parent":"","notes":"","stock_symbol":"","u_op_dev_version":"","u_restriciton":"No","discount":"","sys_id":"7a2c008c1b07ac50a62cea0ce54bcbe8","market_cap":"0","customer":"false"}}
I tried the below query, but it's not giving the expected results it prints out everything after sys_id:
SELECT
Substring (
a.Complete_JSON_Repsone,
Charindex( '"sys_id":', Complete_JSON_Repsone) + 1,
Len(Complete_JSON_Repsone)
) AS [Sys_Idd]
FROM <table-name> a
Current output (actual result):
Sys_Idd
sys_id":"7a2c008c1b07ac50a62cea0ce54bcbe8","market_cap":"0","customer":"false"}}
Expected output:
Sys_Idd
7a2c008c1b07ac50a62cea0ce54bcbe8
UPDATE
Sample Input :
Create table dbo.log1
(
Id varchar(50),
Complete_JSON_Response nvarchar(max),
Sys_Id varchar(50)
)
insert into dbo.log1 (Id,Complete_JSON_Response)
values ('S1','{"result":{"banner_image_light":"","country":"USA","parent":"","notes":"","stock_symbol":"","u_op_dev_version":"","u_restriciton":"No","discount":"","sys_id":"7a2c008c1b07ac50a62cea0ce54bcbe8","market_cap":"0","customer":"false"}}')
,('S2','{"result":{"banner_image_light":"","country":"Aus","parent":"","notes":"","stock_symbol":"","u_op_prod_version":"","u_restriciton":"No","discount":"","sys_id":"5b2c008c1b07ac50a62cea0ce54bcbe8","market_cap":"1","customer":"TRUE"}}')
select * from dbo.log1
Above select query prints, NULL value for Sys_id column as value for that column in not inserted initially. what I want in expected output is that instead of NULL it should populate(derive) only sys_id value from Complete_JSON_Response column to Sys_id column
Expected output:
Id Sys_Id
S1 7a2c008c1b07ac50a62cea0ce54bcbe8
S2 5b2c008c1b07ac50a62cea0ce54bcbe8
SQL Server 2016 supports JSON, so you may try to use JSON_VALUE():
SELECT JSON_VALUE(Complete_JSON_Response, '$.result.sys_id') AS sys_id
FROM (VALUES
(N'{
"result":{
"banner_image_light":"",
"country":"USA",
"parent":"",
"notes":"",
"stock_symbol":"",
"u_op_dev_version":"",
"u_restriciton":"No",
"discount":"",
"sys_id":"7a2c008c1b07ac50a62cea0ce54bcbe8",
"market_cap":"0",
"customer":"false"
}
}')
) a (Complete_JSON_Response)
As an additional option, you may create a simplified UDF with a recursive search:
CREATE FUNCTION dbo.ParseJson (
#json nvarchar(max),
#key nvarchar(max)
)
RETURNS #ResultTable TABLE (
[value] nvarchar(max)
)
AS
BEGIN
;WITH rCTE AS (
SELECT
CONVERT(nvarchar(max), N'$') COLLATE DATABASE_DEFAULT AS [path],
CONVERT(nvarchar(max), JSON_QUERY(#json, '$')) COLLATE DATABASE_DEFAULT AS [value]
UNION ALL
SELECT
CONVERT(nvarchar(max), c.[key]) COLLATE DATABASE_DEFAULT,
CONVERT(nvarchar(max), c.[value]) COLLATE DATABASE_DEFAULT
FROM rCTE r
CROSS APPLY OPENJSON(r.[value]) c
WHERE ISJSON(r.[value]) = 1
)
INSERT INTO #ResultTable ([value])
SELECT [value]
FROM rCTE
WHERE (ISJSON([value]) = 0) AND (path = #key)
RETURN
END
Statement:
DECLARE #json nvarchar(max) = N'
{
"result":{
"banner_image_light":"",
"country":"USA",
"parent":"",
"notes":"",
"stock_symbol":"",
"u_op_dev_version":"",
"u_restriciton":"No",
"discount":"",
"sys_id":"7a2c008c1b07ac50a62cea0ce54bcbe8",
"market_cap":"0",
"customer":"false"
},
"result2":{
"sys_id":"xxxx008c1b07ac50a62cea0ce54bcbe8"
}
}
'
SELECT j.[value] AS sys_id
FROM (VALUES (#json)) a (Complete_JSON_Response)
OUTER APPLY dbo.ParseJson(a.Complete_JSON_Response, 'sys_id') j
Result:
sys_id
--------------------------------
xxxx008c1b07ac50a62cea0ce54bcbe8
7a2c008c1b07ac50a62cea0ce54bcbe8
You can use a function. It may lead some performance issues but works fine.
select
'{"result":{"banner_image_light":"","country":"USA","parent":"","notes":"","stock_symbol":"","u_op_dev_version":"","u_restriciton":"No","discount":"","sys_id":"7a2c008c1b07ac50a62cea0ce54bcbe8","market_cap":"0","customer":"false"}}' json
into tmp_json
CREATE FUNCTION dbo.trialFnc(
#json nvarchar(max),
#key nvarchar(255)
)
RETURNS nvarchar(255)
AS
BEGIN
declare #txt1 nvarchar(max) = right(#json, len(#json) - (charindex(#key, #json)) + 1 - len(#key) - 3)
declare #txt2 nvarchar(max) = left(#txt1, charindex('"', #txt1) - 1)
RETURN #txt2
END;
select
dbo.trialFnc(json, 'country') country
, dbo.trialFnc(json, 'sys_id') sys_id
from tmp_json
It will return you this:
country
sys_id
USA
7a2c008c1b07ac50a62cea0ce54bcbe8

Transform a SELECT * query to string

I have a query that returns a row
SELECT *
FROM table
WHERE id = 1;
I want to save the result into a nvarchar sql variable. I have seen similar questions Convert SQL Server result set into string but they only use select with the name of the columns, never with *.
select *
from table
where id = 1
for xml path ('')
However the answer is <column1>value1</column1> <column2>value2</column2> and I just want it to be value1, value2
Is there a way to achieve this? thank you!
If open to a helper function.
This will convert virtually any row, table or query to a string (delimited or not).
In the following examples I selected a PIPE delimiter with a CRLF line terminator.
Please note the usage and placement of _RN when a line terminator is required. Also note the ,ELEMENTS XSINIL ... this will included null values as empty string. If you want to exclude null values, simply omit the ,ELEMENTS XSINIL
Example as Entire Table or dbFiddle
Declare #YourTable Table (id int,[col_1] varchar(50),[col_2] varchar(50),[col_3] varchar(50),[col_n] varchar(50)) Insert Into #YourTable Values
(1,'data1','data2','data3','data4')
,(2,'data5','data6','data7','data8')
-- Entire Table
Declare #XML xml = (Select *,_RN=Row_Number() over (Order By (Select null)) From #YourTable for XML RAW,ELEMENTS XSINIL )
Select [dbo].[svf-str-Data-To-Delimited]('|',char(13)+char(10),#XML)
Returns
1|data1|data2|data3|data4
2|data5|data6|data7|data8
Example as Row Based
Select A.ID
,AsAString = [dbo].[svf-str-Data-To-Delimited]('|',char(13)+char(10),B.XMLData)
From #YourTable A
Cross Apply ( values ( (select a.* for xml RAW,ELEMENTS XSINIL )) )B(XMLData)
Returns
ID AsAString
1 1|data1|data2|data3|data4
2 2|data5|data6|data7|data8
The Function if Interested
CREATE Function [dbo].[svf-str-Data-To-Delimited] (#Delim varchar(50),#EOL varchar(50),#XML xml)
Returns varchar(max)
Begin
Return(
Select convert(nvarchar(max),(
Select case when Item='_RN' then ''
else case when nullif(lead(Item,1) over (Order by Seq),'_RN') is not null
then concat(Value,#Delim)
else concat(Value,#EOL)
end
end
From (
Select Seq = row_number() over(order by (select null))
,Item = xAttr.value('local-name(.)', 'nvarchar(100)')
,Value = xAttr.value('.','nvarchar(max)')
From #XML.nodes('/row/*') xNode(xAttr)
) A
Order By Seq
For XML Path (''),TYPE).value('.', 'nvarchar(max)') )
)
End
You can easily store the result as an XML string:
select *
from (values (1, 'x', getdate())) v(id, a, b)
where id = 1
for xml path ('');
Or as a JSON string:
select *
from (values (1, 'x', getdate())) v(id, a, b)
where id = 1
for json auto;
If you don't mind Using dynamic SQL (and INFORMATION_SCHEMA dictionary), for example, for SQL Server this works:
DECLARE #sql nvarchar(max) = '',
#result nvarchar(max),
#id int = 1
SELECT #sql += '+'',''+convert(nvarchar,' + QUOTENAME(column_name) +')' from INFORMATION_SCHEMA.columns where table_name = 'Student'
SET #sql = 'select #result=' + stuff(#sql,1,5,'') + ' from student where id = ' + CAST(#id as nvarchar)
EXECUTE sp_executesql #sql, N'#result nvarchar(max) OUTPUT', #result=#result OUTPUT
SELECT #result as MyOutput

Create Shortcut Function in T-SQL

Using the code below I can create a comma separated list of results from the results of a select statement:
DECLARE #lst NVARCHAR(MAX) = ''
SELECT #lst = COALESCE(NULLIF(#lst,'')+N',',N'') + [colName]
FROM [tableName]
I would like to transform this into a sort of shortcut function, for example:
SELECT dbo.fnColAsList([colName])
FROM [tableName]
Is this at all possible?
Edit:
To give an example, if the select statement returned the following 3 columns:
SELECT [colName] FROM [tableName]
>>> colName
-----------
[1] foo1
[2] foo2
[3] foo3
Then the code would produce a single varchar field:
SELECT #lst = COALESCE(NULLIF(#lst,'')+N',',N'') + [colName]
FROM [tableName];
SELECT #lst
>>> lst
---------
[1] foo1,foo2,foo3
I wish to produce a shortcut so that I can call the code around any column so for example I could do this:
SELECT fnColAsList(colName) AS 'x' FROM [tab1];
>>> x
-----------------
[1] tab1Col1,tab1Col2,tab1Coln
SELECT fnColAsList(colName) AS 'y' FROM [tab2];
>>> y
-----------------
[1] tab2Col1,tab2Col2,tab2Coln
Answered:
CREATE FUNCTION dbo.fnColAsList(#rawxml XML)
RETURNS NVARCHAR(MAX)
AS
BEGIN
RETURN STUFF(((SELECT ',' + AllAttribs.value(N'.','nvarchar(max)')
FROM #rawxml.nodes('/row/#*') x (AllAttribs)
FOR XML PATH(''),ROOT('x'),TYPE).value('/x[1]','VARCHAR(MAX)')
),1,1,'');
END
GO
SELECT dbo.fnColAsList((SELECT [colName] FROM tabName FOR XML RAW))
You can try a trick: Pass in the SELECT as XML by wrapping it in paranthesis. XML is - other than pure SQL - much mightier in dealing with generic names:
CREATE FUNCTION dbo.TestCSV(#SelectForXMLRaw XML)
RETURNS NVARCHAR(MAX)
AS
BEGIN
RETURN STUFF(
(
SELECT ',' + AllAttribs.value(N'.','nvarchar(max)')
FROM #SelectForXMLRaw.nodes('/row/#*') x(AllAttribs)
FOR XML PATH(''),TYPE
).value(N'.','nvarchar(max)'),1,1,''
);
END
GO
DECLARE #tbl TABLE(ID INT IDENTITY,col1 VARCHAR(100),col2 VARCHAR(100),col3 VARCHAR(100));
INSERT INTO #tbl VALUES ('1a','2a','3a'),('1b','2b','3b');
SELECT ID
,dbo.TestCSV((SELECT * FROM #tbl AS t2 WHERE t2.ID=t.ID FOR XML RAW)) AS Concatenated
FROM #tbl AS t
GO
DROP FUNCTION dbo.TestCSV;
The result
ID Concatenated
1 1,1a,2a,3a
2 2,1b,2b,3b
UPDATE According to your edits
From you edits I take, that you need this for row-wise data. You can achieve this with the same function actually. Just try this
DECLARE #tbl2 TABLE(SomeUnknownColumn VARCHAR(100));
INSERT INTO #tbl2 VALUES ('Val 1'),('Val 2'),('Val 3');
SELECT dbo.TestCSV((SELECT * FROM #tbl2 FOR XML RAW)) AS Concatenated
Thne result:
Val 1,Val 2,Val 3

Different SQL Select query

I need to write SQL query in order to extract some data.
i have this data in my table:
ID Store Value
1 9921 NOK
2 9921 NOK1
3 9921 OK3
what i need is to get data from select query like this form:
9921 NOK,NOK1,OK3
Any help please ?
You can use STUFF:
SELECT DISTINCT Store,
STUFF((SELECT ',' + Value
FROM Your_Table
WHERE Store = 9921
FOR XML PATH('')), 1, 1, '')
FROM Your_Table
Try to accomplish your excepted output by using COALESCE;
Create a sample table for testing purpose
CREATE TABLE SampleData (id INT ,store INT ,value NVARCHAR(50))
INSERT INTO SampleData VALUES (1 ,9921 ,'NOK')
INSERT INTO SampleData VALUES (2 ,9921 ,'NOK1')
INSERT INTO SampleData VALUES (3 ,9921 ,'NOK2')
Create a Scalar-Valued Function
Alter FUNCTION fun_GetCombinedData
(
#store int
)
RETURNS nvarchar(max)
AS
BEGIN
-- Declare the return variable here
DECLARE #CombineValue nvarchar(max)
SELECT #CombineValue = COALESCE(#CombineValue + ', ', '') + value
FROM SampleData where store=#store
RETURN #CombineValue
END
GO
Final Query,
SELECT store
,dbo.fun_GetCombinedData(store) AS value
FROM SampleData
GROUP BY store
Expected Output:
store | value
------------------------
9921 | NOK,NOK1,NOK2
This is one of the way to simplify your select query.
Using T-SQL we can do it this way:
declare #store int = 9921, #values varchar(max) = ''
select #values = #values
+ case
when #values = '' then ''
else ','
end + value
from table_name
where store = #store
order by id
select #store, #values
Go through this below example
Demo: [SQLFiddle]
The SQL I used is as below,
SELECT
store,
STUFF(
(SELECT DISTINCT ',' + value
FROM SampleData
WHERE store = a.store
FOR XML PATH (''))
, 1, 1, '') AS CombineValues
FROM SampleData AS a
GROUP BY store
you will see your expected result as "CombineValues"
store CombineValues
9921 NOK,NOK1,NOK2