How to get result with square bracket surrounded to each value when using IN keyword in Pivot table? - sql

I am writing the sql query for creating the pivot table. I have the sample code where I am getting the result without error but the result should be values surrounded by square bracket to each value instead to the whole result. How do I setup for it?
I have tried using quote function but it is putting square bracket around the whole output.
DECLARE #CityNames NVARCHAR(MAX) = '', #t varchar(max) = 'jay, sam'
SELECT #CityNames += QUOTENAME(#t)+ ','
select #CityNames
I expect the output to be [jay],[sam], but the actual output is [jay,sam].

Is this what you want?
select '[' + #t + replace(#t, ', ', '], [') + ']')
QUOTENAME() treats the string as a single identifier, quoting appropriately The above should work for most reasonable column names.

I have found the answer by using QUOTENAME() function, we can follow the below code or above code by #gordon Linoff.
DECLARE #CityNames NVARCHAR(MAX) = '', #t nvarchar(max) = 'jay, sam', #result
varchar(max), #sSQL nvarchar(max)
SELECT #CityNames += + QUOTENAME(value)+',' from (select value from
dbo.fx_split( #t, ','))x
IF (RIGHT(#CityNames, 1) = ',')
set #CityNames = LEFT(#CityNames, LEN(#CityNames) - 1)
select #citynames

Related

Need to add double quotes to SQL SERVER string values

I have integer values that are being passed from a parameter that needed to be input as a string and padded so that they are 7 digits. This will then be passed into another query.
declare #t table(ctl_num int)
insert into #t values(5675, 45464, 2323)
declare #control_num varchar(500)
set #control_num = (select stuff((select ',' + right('000' + cast(ctl_num as varchar),7)
from #t
FOR XML PATH('')),1, 1', ''))
This codes sets #control_num as ('0005675, 0045464, 0002323'). I need this to be passed as ("0005675", "0045464", "0002323").
I've looked at other examples on-line but I can't seem to get this to work. Does anyone know how to get the double quotes around each value?
I think there is some issue in setting #control_num.
Please try the following:
set #control_num = (select stuff((select ',"' + right('000' + cast(ctl_num as varchar),7) + '"'
from #t
FOR XML PATH('')),1, 1, ''))
I would suggest:
select string_agg(concat('"', right('000' + cast(ctl_num as varchar(255)), 7), '"', ',')
from #t;
string_agg() has been available since SQL Server 2017. Also note that you should always include a length when referring to strings in SQL Server.

The argument 1 of the XML data type method “value” must be a string literal

If i pass #count variable i am getting this error
Below is my query
DECLARE #Error_Description NVARCHAR(Max)
DECLARE #Count VARCHAR(20)
DECLARE #x NVARCHAR(Max)
SELECT #Error_Description = 'The external columns for Excel Source are out of synchronization with the data source columns.
The column "szReferencceNumber" needs to be added to the external columns.
The column "SMSa" needs to be added to the external columns.
The column "as" needs to be added to the external columns.'
SELECT #Count = (LEN(#Error_Description) - LEN(REPLACE(#Error_Description, '"', ''))) / LEN('"')
SELECT #Count
SELECT COALESCE(LTRIM(CAST(('<X>' + REPLACE(#Error_Description, '"', '</X><X>') + '</X>') AS XML).value('(/X)[' + #Count + ']', 'varchar(128)')), '')
The first parameter to value must be a string literal. To select the nodes with a dynamic index you can do the following
SELECT
n.value('.', 'varchar(128)') as Result
from (SELECT CAST(('<X>' + REPLACE(#Error_Description, '"', '</X><X>') + '</X>') AS XML)) ca(x)
CROSS APPLY x.nodes('(/X)') n(n)
WHERE n.value('for $l in . return count(../*[. << $l]) + 1', 'int') %2 = 0
This returns the value for every second node. So achieves your desired results of getting the values enclosed in quotes.
Result
---------------------
szReferencceNumber
SMSa
as
if you're using 2012+, and you can use nvarchar(4000) (not MAX), you could get a copy of DelimitedSplitN4K_LEAD and grab rows where the value of ItemNumber is even:
DECLARE #Error_Description nvarchar(4000);
SELECT #Error_Description = N'The external columns for Excel Source are out of synchronization with the data source columns.
The column "szReferencceNumber" needs to be added to the external columns.
The column "SMSa" needs to be added to the external columns.
The column "as" needs to be added to the external columns.';
SELECT DS.Item
FROM dbo.DelimitedSplitN4K_LEAD(#Error_Description,'"') DS
WHERE DS.ItemNumber % 2 = 0;
If you're on SQL server 2016+, then you could use some JSON manipulation (which supports MAX values):
SELECT OJ.value
FROM (VALUES(#Error_Description))V(Error_Description)
CROSS APPLY (VALUES('["' + REPLACE(REPLACE(REPLACE(V.Error_Description,'"','","'),NCHAR(13),''),NCHAR(10),'')+ '"]'))R(JSON)
CROSS APPLY OPENJSON(R.JSON) OJ
WHERE OJ.[Key] % 2 = 1;
You can use your #Count within the XQuery predicate, but not via concatenation. There is sql:variable():
TheXml.value('(/X)[sql:variable("#Count") cast as xs:int?][1]', 'varchar(128)')
It would help to declare the variable #Count as INT in order to avoid the XQuery cast.
Hint: You need the final [1] to enforce the singleton .value() demands for.
this is all based on the #Shnugo answer above, thanks a lot Shnugo
I have a long script saved in to a temp table
select * from #Radhe
I want to print the whole script.
DECLARE #SQL NVARCHAR(MAX)
DECLARE #XML3 XML
--load the script to XML
SELECT #XML3 = (SELECT #Radhe.Item AS x FROM #Radhe FOR XML PATH(''))
--print line by line
declare #i int = 1
select #sql = 'radhe'
while #sql is not null
begin
SELECT #sql = #xml3.value('(/x/text())[sql:variable("#i")
cast as xs:int?][1]', 'varchar(max)')
print #sql
select #i = #i + 1
if #i > 10000 --limit it to 10000 lines
set #sql = null
end
and it works.
It took me a long time to get this done.
Hope I can help a fellow DBA or developer.

Assistance with a SQL query parsing JSON

I have a database table called QueueItems that contains the following fields:
SpecificData contains JSON data so we have used the well known parseJSON SQL function that is about on the internet.
So an example of the JSON is below:
{"DynamicProperties":{"IdentificationIndex":"CK","PaymentMethod":"C","Variants1":"010 ZERO BAL,716 ZERO BAL,717 ZERO BAL","Variants2":"CHECK_010,CHECK_716,CHECK_717","CustomerCode":"NO","FreeSelectionField":"NO","FreeSelectionValue":"NO","Variants1Line":"RFFOAVIS","Variants2Line":"ZRFFOUS_C","VendorFrom":"1","VendorTo":"999999999","DueDateCheck":"Yes","PaymentMethodSel":"Yes","PaymentMethodSelOnFail":"No","LineItemsOfPayDocs":"Yes","StartImmediately":"Yes","CreatePaymentMedium":"No","ExportFormat":"HTML Format","ExcludeValues":"Yes"}}
When I run the SQL function parseJSON it returns me the data in this format:
Now, the query I am trying to write is:
SELECT QueueItemID, QueueItemStatus, StartProcessing, EndProcessing, [THEN append each column from parseJSON but this needs to be transposed first]
So far I have managed to transpose the JSON into columns with a single row using:
DECLARE
#Cols AS VARCHAR(MAX) = ''
,#Query AS NVARCHAR(MAX) = ''
,#ParamDef AS NVARCHAR(MAX)
,#Json AS VARCHAR(MAX) = '{"DynamicProperties":{"IdentificationIndex":"CK","PaymentMethod":"C","Variants1":"010 ZERO BAL,716 ZERO BAL,717 ZERO BAL","Variants2":"CHECK_010,CHECK_716,CHECK_717","CustomerCode":"NO","FreeSelectionField":"NO","FreeSelectionValue":"NO","Variants1Line":"RFFOAVIS","Variants2Line":"ZRFFOUS_C","VendorFrom":"1","VendorTo":"999999999","DueDateCheck":"Yes","PaymentMethodSel":"Yes","PaymentMethodSelOnFail":"No","LineItemsOfPayDocs":"Yes","StartImmediately":"Yes","CreatePaymentMedium":"No","ExportFormat":"HTML Format","ExcludeValues":"Yes"}}'
SELECT
#Cols += ',' + Name
FROM
parseJson(#Json)
WHERE
Name NOT IN ('DynamicProperties', '-')
SET #Cols = SUBSTRING(#Cols,2,LEN(#Cols))
SET #Query = N'SELECT *
FROM
(
SELECT [StringValue], [Name]
FROM parseJson(''' + #Json + ''')
) [d]
PIVOT
(
MAX([StringValue])
FOR [Name] IN (' + #Cols + ')
) [piv]'
EXECUTE (#Query)
As you can see the JSON may contain ANY data, so I am dynamically inserting the column names into the PIVOT statement FOR IN.
Now to Join this data as additional columns onto my main query SELECT QueueItemId.. FROM QueueItems I was originally going to put this code in a UDF and call it as part of my main query / stored procedure but I have two issues:
1) The sp_executesql or EXEC statement - not allowed in a UDF
2) To return a table from a UDF I need to define the fields... The fields are dynamic... I could get this working by passing back XML to my stored procedure but I still have issue number 1.
So the question is:
1) Is there any better way or writing this then using a UDF?
2) Is there any other way or transposing the output from parseJSON?
3) Is there any other way of using the PIVOT but not having to specify the columns?
Any help would be much appreciated.
EDIT IN RESPONSE TO M ALI
I know the syntax is wrong and it doesn't work but the query would look something like this:
DECLARE #Cols AS VARCHAR(MAX) = ''
,#Query AS NVARCHAR(MAX) = ''
SELECT
QI.QueueItemID,
QI.QueueItemStatus,
QI.StartProcessing,
QI.EndProcessing,
SD.*
FROM QueueItems AS QI
LEFT JOIN
(
SELECT
#Cols += ',' + Name
FROM
parseJson(QI.SpecificData)
WHERE
Name NOT IN ('DynamicProperties', '-')
SET #Cols = SUBSTRING(#Cols,2,LEN(#Cols))
SET #Query = N'SELECT *
FROM
(
SELECT [StringValue], [Name]
FROM parseJson(''' + QI.SpecificData + ''')
) [d]
PIVOT
(
MAX([StringValue])
FOR [Name] IN (' + #Cols + ')
) [piv]'
EXECUTE (#Query)
) AS SD
And the results would be the columns from QueueItems, joined on the left by columns from the parsed JSON string.
QueueItemID, StartProcessing, EndProcessing, IndentificationIndex, PaymentMethod etc...

TSQL: How to add automatically select columns

I have a problem and can't solve it. Furthermore I can't find an answer anywhere in the internet.
Simplified I have a big table with coloumns, where values to products with an ID are stored by year:
year
id
value
In my stored procedure the attributes for getting information are:
#year
#id
If you want to get information about more than one product, you can use a comma-seperated list of product-ids like ('654654,543543,987987').
My TSQL should be like this:
select year,
sum(case when id = #id[1] then value),
sum(case when id = #id[2] then value),
[...]
from table myTable
where year = #year
group by year
order by year
What I want to do is iterate throught the comma-seperated ids and for each id, I want to add a new select attribut like this (sum(case when id = #id[x] then value).
Can you help me with this problems? Any suggestions to solve it?!
Thanks for your help!
PIVOT operation could simplify the query.
But, anyway, it seems that the only way to construct such a query is to use dynamic SQL.
DECLARE
#Ids NVARCHAR(MAX),
#stmt NVARCHAR(MAX)
SET #Ids = '1,2'
-- Transform Ids into the format PIVOT understands - with square brackets.
-- Primitive way, to not overcomplicate sample.
SET #Ids = '[' + REPLACE(#Ids, ',', '], [') + ']'
PRINT #Ids -- [1], [2]
SET #Stmt = '
SELECT *
FROM Products as p
PIVOT
(
SUM(p.Value)
FOR p.Id IN (' + #Ids + ')
) AS t
ORDER BY Year'
EXEC sp_executesql #Stmt
If you need more accurate way of splitting a comma separated list into an array (table), please see this article for details.
This example is available on SQL Fiddle
As you are using stored procedure, you can use sp_executesql to executed dynimically build SQL statement.
So, you have to iterate over the CSV like this:
DECLARE #List NVARCHAR(MAX) = N'1001,dada,1002,1003'
DECLARE #ProductsID TABLE ( [ID] BIGINT )
DECLARE #XML xml = N'<r><![CDATA[' + REPLACE(#List, ',', ']]></r><r><![CDATA[') + ']]></r>'
INSERT INTO #ProductsID ([ID])
SELECT DISTINCT CAST(Tbl.Col.value('.', 'float') AS bigint)
FROM #xml.nodes('//r') Tbl(Col)
WHERE ISNUMERIC(Tbl.Col.value('.', 'varchar(max)')) = 1
SELECT [ID] FROM #ProductsID
Then, having a table with the ID to dynamically build you SQL statement and execute it.

Filter fields in 'IN' clause using a variable

I would like to do something like this :
DECLARE #list nvarhcar(200) SET #list = 'VALUE1,VALUE2,VALUE3'
Select * from foo where field in (#list)
Until today I solved using sp_executeSQL procedure, my own database function csv2table and subselect, but I think that is not very clean.
Is there any way to solve without use dynamic sql ? Is there a direct method?
I'm using Microsoft Sql Server 2005.
Thanks!
Would you please try as below: thanks
DECLARE #list nvarchar(200)
SET #list = 'VALUE1,VALUE2,VALUE3'
SELECT * FROM foo WHERE CHARINDEX(',' + field + ',', ',' + #list + ',') > 0
Create Part A as an UDF
/* Part A */
DECLARE #list Varchar(max) = 'VALUE1,VALUE2,VALUE3'
DECLARE #tmpTbl_Values Table (ID varchar(50))
Set #list = #list + ','
-- Indexes to keep the position of searching
Declare #Pos1 Int
Declare #pos2 Int
-- Start from first character
Set #Pos1=1
Set #Pos2=1
While #Pos1<Len(#list)
Begin
Set #Pos1 = CharIndex(',',#list,#Pos1)
Insert #tmpTbl_Values Select Cast(Substring(#list,#Pos2,#Pos1-#Pos2) As varchar(50))
-- Go to next non comma character
Set #Pos2=#Pos1+1
-- Search from the next charcater
Set #Pos1 = #Pos1+1
End
/* Part B */
SELECT *
FROM foo A
INNER JOIN #tmpTbl_Values B
ON AB.ID = B.ID
One alternative:
Select * from foo where '%,' + field + ',%' like ',' + (#list) + ','
This is even "dirtier" than the existing approach.
Ideally, I would suggest changing the query string to:
Select * from foo where field in ()
then reading through the list of values in #list, inserting a ? for each value (separated by commas) and binding each value to that parameter marker. However, I don't know how to achieve this in dynamic SQL alone.
If the datatype for the field is nchar or varchar, the IN() operator will look for value like
IN('VALUE1','VALUE2','VALUE3', etc..)
So you set your #list based on that
A possible approach is to do the following:
SELECT * FROM foo WHERE CHARINDEX(',' + field + ',', ',' + #list + ',') > 0
This is assuming that the data in the field has no comma in it
If you deal with a string field, you could use something like this..
DECLARE #csv varchar(50) = 'item1,item2, item3, item4 ,item5'
SELECT * FROM foo WHERE PATINDEX('%' + Field + '%', #csv) > 0
In SQL 2005 you can use a custom UDF to parse a delimited list into a table - please see this article http://www.sommarskog.se/arrays-in-sql-2005.html