Result Set of procedure into XML - sql

how can we convert the result set of a procedure into an XML without creating a temporary table since the result set may vary in their structure based on the inputs ? the scenario must work in both on premise and azure hosted SQL server databases.
CREATE PROCEDURE SPSample(#Scope VARCHAR(2))
AS
BEGIN
IF(#Scope='A')
SELECT 1 AS ID,2 AS NAME
IF(#Scope='B')
SELECT 1 AS CustomerID,'Sample#sample.com' AS Email,'121314' AS ContactNumber
END

I believe you are asking to use FOR XML or FOR XML AUTO:
https://learn.microsoft.com/en-us/sql/relational-databases/xml/for-xml-sql-server?view=sql-server-2017
create table mytable(col1 int, col2 nvarchar(20), col3 money)
insert into mytable(col1, col2, col3) values (1, 'string', 123.45)
select * from mytable
for xml auto
Emits:
You can do this on any query result set:
select * from sys.objects
for xml auto
This will emit that structure similarly.

i need a way that the result set from a stored procedure directly converted to XML object without creating a table structure since the result set from procedure may vary
There's no way in TSQL to do that. TSQL can only convert to XML using a SELECT, not an EXECUTE. You could do this with a loopback linked server or CLR, but those are hacks, and not available in Azure SQL DB. You'll have to find another way. EG
CREATE PROCEDURE SPSample(#Scope VARCHAR(2), #ResultsAsXml bit = 0)
. . .

Related

Returning a declared array in stored procedure

I'm currently stuck on a problem with a stored procedure. I have to return an array / list of calculated data from that stored procedure.
Retrieving it with a server using Entity Framework but the problem isn't here.
I want to return data that are like this:
field1 : int,
field2 : string,
field3 : int,
calculatedData : List<int>
At the moment my procedure looks like this:
CREATE PROCEDURE [dbo].[SP_GDF_UNITE_Previsionnel]
AS
DECLARE #calculatedData TABLE(jour int, valeur int)
SELECT
field1,
field2 ,
field3
FROM
(... content )
...
I would like to return the calculatedData but I don't have any idea how to do it.
Maybe by changing my procedure structure ?
Hope someone could help me to do it.
Tried to include the array in my select but doesn't work. Didn't find any information on how to do it on internet. The SELECT ... FROM has to be here in the procedure.
method 1
return an json structure from your select statement. The nest json will act like an array in your json data. Based on your example, the json subquery can have one or more records.
Now you can convert the json data to a diction in python and retrieve the values recursively
/****** Script for SelectTopNRows command from SSMS ******/
select
Field1
,Field2
,Field3
,(select * from dbo.myTable myTable2
where myTable2.Field1=myTable.Field1
for json path) as data
FROM dbo.myTable myTable
where myTable.Field1=123
for json path
method 2
try creating a temp table instead of an array then insert values into the temp table.
declare #tmp_table as table(newid uniqueidentifier , field1 varchar(10));
insert into #tmp_table(newid,field1) values(newid(),'a'),(newid(),'b')
select * from #tmp_table
you can now use the newid as a hashkey for updating the table similar to a dictionary which simulates an array.

Xml file node reading and inserting as seperate rows in a table

I am new bee in learning microsoft technologies.
I struck with an issue in sql server where I need your help.
Well, I have a XML file with below format,
please see it for your reference
<Permissions><Denied><User/><Roles/><Groups/></Denied><Allowed><Users/><Roles>admin,user,reader,writer,</Roles><Groups/></Allowed></Permissions>
In which I need to read Roles node values and insert those comma separated values as single row where I I will pass permissionid as a parameter in stored procedure.
here is the table columns (I need to insert single role for single row in test table based on transitionid)
create table test
(
empid int identity(1,1),
roles varchar(40),
transitionid int
)
You have two problems here: getting the data from the XML and splitting it.
If you're using SQL 2016 you're in luck - there's a new STRING_SPLIT function. You could use that like so:
declare #xml xml = '<Permissions><Denied><User/><Roles/><Groups/></Denied><Allowed><Users/><Roles>admin,user,reader,writer,</Roles><Groups/></Allowed></Permissions>';
declare #test table
(
empid int identity(1,1),
roles varchar(40),
transitionid int
)
INSERT #test (roles)
select b.value
FROM #xml.nodes('//Roles/text()')x(csv)
CROSS APPLY STRING_SPLIT(CAST(x.csv.query('.') AS VARCHAR(MAX)), ',')b
where b.value <> ''
select * from #test
Otherwise, you'll have to do something similar using a custom string splitting method, which you can find more about How do I split a string so I can access item x? or https://sqlperformance.com/2012/07/t-sql-queries/split-strings - basically, both require either writing a custom T-SQL function or CLR code that is imported into SQL Server. You could then use the same method as above (replacing STRING_SPLIT with the name of your custom string splitting function).

How do I use collection as a parameter in SQL Server (2008) SP?

So, I have this stored procedure (let's call it SP1) that gets as parameters two strings (say string1 and string2)
However, I need to call this stored procedure a lot from my code, so in order to make things faster, I was thinking of doing it in bulk. Collecting all of the parameters into a collection of some sort, and then send this.
From what I understand I need to use a DataTable on the code side, and a custom table type as the parameter on the SQL Server side - ok, cool. But...now what?
But... how do I get from there to the point where I actually go
EXEC SP1 string1, string2 or something along those lines?
Not sure whether this is what you like to achieve, instead of parsing those two string parameters, you would like to get a table holding all of the string row?
If so, you could you use UDF within SP,
Check here:
CREATE FUNCTION [dbo].[Name]
(
#parameter
)
RETURNS #Table TABLE
(
col1 varchar(50),
col2 varchar(50)
)
AS
BEGIN
**the query that inserts each records to TABLE**
END
Then using this [Name] UDF in your SP
Create a table type
CREATE TYPE Strings AS TABLE ( String1 VARCHAR(50), String2 VARCHAR(50) )
Alter your procedure to accept table type as input
ALTER PROCEDURE Usp_procname (#strings STRINGS Readonly)
AS
..
To call the procedure
DECLARE #strings STRINGS
INSERT INTO #strings
(String1,String2)
SELECT 'String1','String2'
UNION ALL
SELECT 'String3','String4'
UNION ALL
SELECT 'String5','String6'
EXEC Usp_procname #strings
By this way you can pass more than one string in a single call. Make sure you update the logic inside the procedure to handle more than one string
In a case like this one, I usually concatenate strings and split them on the server side or pass even an xml if I have multiple columns. Sql it's very fast when processing xml. You can try all the methods and check the processing time and after that choose the best method.

How to column schema of arbitrary query in SQL server

I want to get just schema of arbitrary sql query in SQL server.
For example-
Create Table Tabl1(Ta1bID int ,col1 varchar(10))
Create Table Tabl2(Tab1ID int ,col2 varchar(20))
SQL Query -
SELECT col1, col2
FROM Tab1
INNER JOIN Tab2 ON Tab1ID = Tab2ID
Here result will have this schema-
Col1 varchar(10), Col2 varchar(20)
I want to know what will be schema of result.
PS : I have just read access on the server where I am executing this query.
Any way to do this?
The schema, you mean to say datatype right? For resulted datatype will you always know when you operate on table(s). In your case both column is varchar datatype, so it will give character datatype, that you may convert into any character datatype like varchar, nvarchar, char, ntext etc.
Basic thing is, table designing was/is done by, so that time we know why we define datatype, now when you execute query below , you always know what will come with datatype of each column.
SELECT col1, col2
FROM Tab1
INNER JOIN Tab2 ON Tab1ID = Tab2ID
This though will issue when you use dynamic query, where you run time add column as per your requirement and you then execute which may or may not give error, due to mismatch of wrong datatype.
like
declare #sqlstring nvarchar(max)
set #sqlstring = 'declare #t table (name varchar(50))
insert into #t values(''Minh''),(''Tinh''),(''Justin'')
Select * from #t where Name like ''%in%'''
EXEC sp_executesql #sqlstring
I had similar problem before, but I had to create tables (70+) of each query one by one.
If there is a pattern, write a tool to generate create table
statement.
If not and it's one time job, just create them manually.
If it's not one time job, you might be thinking, why would store temp
date in table instead of temp table.

SQL Server - Replacing Single Quotes and Using IN

I am passing a comma-delimited list of values into a stored procedure. I need to execute a query to see if the ID of an entity is in the comma-delimited list. Unfortunately, I think I do not understand something.
When I execute the following stored procedure:
exec dbo.myStoredProcedure #myFilter=N'1, 2, 3, 4'
I receive the following error:
"Conversion failed when converting the varchar value '1, 2, 3, 4' to data type int."
My stored procedure is fairly basic. It looks like this:
CREATE PROCEDURE [dbo].[myStoredProcedure]
#myFilter nvarchar(512) = NULL
AS
SET NOCOUNT ON
BEGIN
-- Remove the quote marks so the filter will work with the "IN" statement
SELECT #myFilter = REPLACE(#myFilter, '''', '')
-- Execute the query
SELECT
t.ID,
t.Name
FROM
MyTable t
WHERE
t.ID IN (#myFilter)
ORDER BY
t.Name
END
How do I use a parameter in a SQL statement as described above? Thank you!
You could make function that takes your parameter, slipts it and returns table with all the numbers in it.
If your are working with lists or arrays in SQL Server, I recommend that you read Erland Sommarskogs wonderful stuff:
Arrays and Lists in SQL Server 2005
You need to split the string and dump it into a temp table. Then you join against the temp table.
There are many examples of this, here is one at random.
http://blogs.microsoft.co.il/blogs/itai/archive/2009/02/01/t-sql-split-function.aspx
Absent a split function, something like this:
CREATE PROCEDURE [dbo].[myStoredProcedure]
#myFilter varchar(512) = NULL -- don't use NVARCHAR for a list of INTs
AS
SET NOCOUNT ON
BEGIN
SELECT
t.ID,
t.Name
FROM
MyTable t
WHERE
CHARINDEX(','+CONVERT(VARCHAR,t.ID)+',',#myFilter) > 0
ORDER BY
t.Name
END
Performance will be poor. A table scan every time. Better to use a split function. See: http://www.sommarskog.se/arrays-in-sql.html
I would create a function that takes your comma delimited string and splits it and returns a single column table variable with each value in its own row. Select that column from the returned table in your IN statement.
I found a cute way of doing this - but it smells a bit.
declare #delimitedlist varchar(8000)
set #delimitedlist = '|1|2|33|11|3134|'
select * from mytable where #delimitedlist like '%|' + cast(id as varchar) + '|%'
So... this will return all records with an id equal to 1, 2, 33, 11, or 3134.
EDIT:
I would also add that this is not vulnerable to SQL injection (whereas dynamic SQL relies on your whitelisting/blacklisting techniques to ensure it isn't vulnerable). It might have a performance hit on large sets of data, but it works and it's secure.
I have a couple of blog posts on this as well, with a lot of interesting followup comments and dialog:
More on splitting lists
Processing list of integers