Collect id's of ALL inserted records as result set - sql

I need a stored procedure which returns resultset of IDs for created records. I've already read that SCOPE_IDENTITY gives only last ID. but my SQL skill is not enough to solve this particular case and get all IDs as the output.
here's what I have for now - this only gets the last record's id
USE AdventureWorks2008;
DELETE FROM [HumanResources].[Shift] where [HumanResources].[Shift].Name='c' or [HumanResources].[Shift].Name='d'
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'ShiftUpdateXml')
DROP PROCEDURE ShiftUpdateXml
GO
CREATE PROCEDURE ShiftUpdateXml
#strXML XML, #ShiftID [tinyint] = NULL OUTPUT
AS
BEGIN
SET NOCOUNT ON;
INSERT [HumanResources].[Shift](Name,StartTime,EndTime) SELECT
TEMP.Name,TEMP.StartTime,TEMP.EndTime
FROM (SELECT
assignreassignro.value('Name[1]','nvarchar(50)') AS Name,
assignreassignro.value('StartTime[1]','time(7)') AS StartTime,
assignreassignro.value('EndTime[1]','time(7)') AS EndTime
FROM #strXML.nodes('documentelement/assignreassignro')Documentelement(assignreassignro)) AS TEMP
SET #ShiftID = SCOPE_IDENTITY();
END
GO
DECLARE #ShiftID INT;
DECLARE #XmlVal XML= '<?xml version="1.0"?>
<documentelement>
<assignreassignro>
<Name>c</Name>
<StartTime>10:30:00.0000000</StartTime>
<EndTime>17:30:00.0000000</EndTime>
</assignreassignro>
<assignreassignro>
<Name>d</Name>
<StartTime>11:00:00.0000000</StartTime>
<EndTime>18:00:00.0000000</EndTime>
</assignreassignro>
</documentelement>'
EXEC ShiftUpdateXml #XmlVal,#ShiftID = #ShiftID OUTPUT;
PRINT #ShiftID;

You are looking for the output clause. If you just want the ids, you can do:
DECLARE #ids TABLE (id int);
INSERT [HumanResources].[Shift](Name,StartTime,EndTime)
OUTPUT inserted.Id INTO #ids
SELECT assignreassignro.value('Name[1]', 'nvarchar(50)') AS Name,
assignreassignro.value('StartTime[1]', 'time(7)') AS StartTime,
assignreassignro.value('EndTime[1]', 'time(7)') AS EndTime
FROM #strXML.nodes('documentelement/assignreassignro') Documentelement(assignreassignro);
If you want additional values, you can add them to the table and the INSERT statement.
Also, note that you do not need a subquery for the SELECT.

To get multiple rows you'll need to use output from the table inserted with something like this:
CREATE PROCEDURE ShiftUpdateXml
#strXML XML
AS
BEGIN
INSERT [Shift](Name,StartTime,EndTime)
output inserted.id
SELECT
TEMP.Name,TEMP.StartTime,TEMP.EndTime
FROM (SELECT
assignreassignro.value('Name[1]','nvarchar(50)') AS Name,
assignreassignro.value('StartTime[1]','time(7)') AS StartTime,
assignreassignro.value('EndTime[1]','time(7)') AS EndTime
FROM #strXML.nodes('documentelement/assignreassignro')Documentelement(assignreassignro)) AS TEMP
END
That way the procedure will return the list of IDs. I made an example into SQL Fiddle

Related

How to get the particular column value of the EXEC result in SQL?

I'm executing a query like
EXEC [dbo].[GET_ALL_RECORDS] #ProjectId
GET_ALL_RECORDS SP is used to retrieve all the records
Here I'm passing Project Id as a Parameter to fetch records for only that project Id.
I'm getting result like
A B C D
value1 value2 value3 value4
Where A B C D are column names.
I want to get the value of D column.
How can I modify the above query (
EXEC [dbo].[GET_ALL_RECORDS] #ProjectId ) to get the column D value?
Which is the best way to retrieve that?
If procedure is returning table type output then you must create a similar schema of that output table, you may create #temp table for that.
Stores output of procedure in table then retrieve your data from temp table.
Example is like this:
CREATE TABLE #TestTable ([col1] NVARCHAR(100), [col2] NVARCHAR(100));
INSERT INTO #TestTable
EXEC [dbo].[GET_ALL_RECORDS] #ProjectId --- expecting #ProjectId is the variable in which you want to get the result
declare #output nvarchar(100)
set #output = (select top 1 col from #TestTable order by col )
Or if you can modify procedure then this will be your solution
create proc myproc
as
begin
----- do your code here
declare #output nvarchar(100)
set #output = (select top 1 col from #TestTable order by col ) ---- assuming #TestTable is the table you get as output.
return #output
end
go
declare #op nvarchar(100)
exec #op = myproc
If the code of your stored procedure is compatible with UDF limitations, you should consider transforming it into a user defined function returning a table.
Thus you can use it in an expression like:
SELECT D FROM [dbo].[GET_ALL_RECORDS](#ProjectId)
while you will still be able to use all the fields whenever appropriate:
SELECT * FROM [dbo].[GET_ALL_RECORDS](#ProjectId)

Insert Query to insert multiple rows in a table via select and output clause. SQL Server 2008

I have a created a stored procedure (please ignore syntax errors)
alter proc usp_newServerDetails
(#appid int, #envid int, #serType varchar(20), #servName varchar(20))
as
declare #oTbl_sd table (ID int)
declare #outID1
declare #oTbl_cd table (ID int)
declare #outID2
begin Transaction
insert into server_details(envid, servertype, servername)
output inserted.serverid into #oTbl_sd(ID)
values(#envid, #serType, #servName)
select #outID1 = ID from #oTbl_sd
insert into configdetails(serverid, servertype, configpath, configtype)
output inserted.configid into #oTbl_cd(ID)
(select #outID1, cm.servertype, cm.configpath, cm.configtype
from configpthmaster cm
where cm.appid = #appid )
select #outID2 = ID from #oTbl_cd
insert into configkeydetails(confiid, keyname)
output inserted.Keyid into #oTbl_ckd(ID)
(select #outID2, cm.key
from configpthmaster cm
where cm.appid = #appid)
begin
commit
end
server_details table has an identity column ID with is auto-generated ie. #outID1 and first insert query inserts only 1 row.
configpthmaster table is not related to any other table directly and has 2 unique data rows, which I want to fetch to insert data into other tables, one by one during insertion.
The second insert query fetch data from configpthmaster table
and insert 2 rows in configdetails while generating (auto-generated) ID ie. #outID2.
It also has a FK mapped to server_details.
The problem is "#outID2" giving last inserted ID only (ie. if two id generated 100,101 i am getting 101) which eventually on 3rd insertion, inserting 2 rows with same id 101 only but i want the insertion should be linear. i.e one for 100 and other for 101.
If zero rows affected while insertion how to rollback the transaction?
How can I achieve these requirements? Please help.
Change your procedure like below,and try again.
ALTER PROCEDURE usp_newServerDetails(#appid int, #envid int,#serType varchar(20),#servName varchar(20))
AS
BEGIN
BEGIN TRY
DECLARE #Output TABLE (ID int,TableName VARCHAR(50),cmKey VARCHAR(50)) --table variable for keeping Inserted ID's
BEGIN TRAN
IF EXISTS ( SELECT 1 FROM configpthmaster cm WHERE cm.appid = #appid )
AND ( SELECT 1 FROM configkeydetails ck WHERE ck.appid = #appid ) --add a conditon to satisfy the valid insertions
BEGIN
INSERT INTO server_detials(envid,servertype,servername)
OUTPUT inserted.serverid,'server_detials',NULL INTO #Output(ID,TableName,cmKey )
VALUES(#envid ,#serType ,#servName)
INSERT INTO configdetails(serverid,servertype,configpath,configtype)
OUTPUT inserted.configid,'configdetails',cm.Key INTO #Output(ID,TableName,cmKey )
SELECT t.ID,cm.servertype,cm.configpath,cm.configtype
FROM configpthmaster cm
CROSS APPLY (SELECT ID FROM #Output WHERE TableName='server_detials')t
WHERE cm.appid = #appid
INSERT INTO configkeydetails(configId,keyname)
SELECT ID,cmKey FROM #Output
WHERE TableName='configdetails'
END
COMMIT TRAN
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK
END CATCH
END
Could you try this solution?
alter proc usp_newServerDetails(#appid int, #envid int,#serType varchar(20),#servName varchar(20))
as
declare #oTbl_sd table (ID int)
declare #outID1
declare #oTbl_cd table (ID int)
declare #outID2
begin Transaction
insert into server_detials(envid,servertype,servername)
output inserted.serverid into #oTbl_sd(ID)
values(#envid ,#serType ,#servName)
select #outID1 = ID from #oTbl_sd
insert into configdetails(serverid,servertype,configpath,configtype)
output inserted.configid into #oTbl_cd(ID)
(select #outID1 ,cm.servertype,cm.configpath,cm.configtype from configpthmaster cm where cm.appid = #appid )
select #outID2 = ID from #oTbl_cd
insert into configkeydetails(confiid,keyname)
output inserted.Keyid into #oTbl_ckd(ID)
(select isnull(replace(stuff((SELECT inserted.configid FOR xml path('')), 1, 1, ''), '&', '&'), '') ,cm.key, from configpthmaster cm where cm.appid = #appid )
begin
commit
end
I just added STUFF in your code.
The STUFF function inserts a string into another string.
Do take note that using STUFF drastically slows the processing time of the code.
for more information about STUFF

Iterate through values of a table variable in a stored procedure

I am writing a stored proc as follows:
CREATE PROCEDURE ListByOrderRequestId
#EntityId int,
#EntityTypeId varchar(8)
AS
BEGIN
SET NOCOUNT ON;
Declare #IDS table(OrderRequestId int)
INSERT INTO #IDS
SELECT OrderRequestTaskId
FROM OrderRequestTask ORT WITH (NOLOCK)
WHERE ORT.OrderRequestId = #EntityId
SELECT N.EntityNoteId AS Id,
N.UpdateDate AS DateStamp,
N.EntityNoteText,
N.EntityId,
N.EntityNoteTypeId,
N.EntityTypeId
FROM EntityNote N
WHERE (N.EntityId = #EntityId AND N.EntityTypeId ='ORDREQ')
*OR(N.EntityId = #IDS VAL1 AND N.EntityTypeId ='TASK')
OR(N.EntityId = #IDS VAL2 AND N.EntityTypeId ='TASK')*
END
The table #IDS can have 0 or 1 or more values in it. I want to loop through the values in #TDS and create the where clause above accordingly. Please help me.
As opposed to looping through the table, you could just use it in your where clause like this:
Select * From {Your Table} Where ID in (Select OrderRequestId From IDS)
This is much faster than looping.

SQL - Getting Updated Value

I use Sql Server 2008.
I have a table that generates ID.
I want to retrieve the generated ID and store it in a bigint variable.
How can I do it?
Here is the Stored Proc that gives the ID as result set. But I cannot store it in a bigint variable.
ALTER PROC SCN.TRANSACTION_UNIQUE_ID_SELECT
AS
UPDATE COR.TRANSACTION_UNIQUE_ID
SET ID = ID + 1
OUTPUT INSERTED.ID AS ID
If you want to use output you can;
declare #ID table (ID bigint)
update the_table
set ID = ID + 1
output INSERTED.ID into #ID
declare #bi bigint = (select ID from #ID)
The BigInt should be an identity insert column, this will make SQL Server automatically generate bigints in sequence for you. Just pass the rowID as an OUTPUT parameter and set it before the procedure ends after the insert/update.
Then you can read it coming back and set it as needed.
The stored procedure could look something like this (I've only included the rowID for clarity):
CREATE PROCEDURE [Sample].[Save]
(
#rowID bigint OUTPUT
)
AS
BEGIN
SET NOCOUNT ON
--Do your insert/update here
--Set the RowID
SET #rowID = (SELECT SCOPE_IDENTITY())
END
That UPDATE looks fishy...it will increment every ID in your table by one, no?
Anyway, variables have an #sign, so just SET #myvar = ...whatever...
Use OUTPUT INTO:
DECLARE #TblID TABLE ( ID int )
UPDATE COR.TRANSACTION_UNIQUE_ID
SET ID = ID + 1
OUTPUT INSERTED.ID INTO #TblID (ID) --the output values will be inserted
--into #TblID table-variable
DECLARE #id BIGINT
EXEC #id = SCN.TRANSACTION_UNIQUE_ID_SELECT

Pass table as parameter into sql server UDF

I'd like to pass a table as a parameter into a scaler UDF.
I'd also prefer to restrict the parameter to tables with only one column. (optional)
Is this possible?
EDIT
I don't want to pass a table name, I'd like to pass the table of data (as a reference I presume)
EDIT
I would want my Scaler UDF to basically take a table of values and return a CSV list of the rows.
IE
col1
"My First Value"
"My Second Value"
...
"My nth Value"
would return
"My First Value, My Second Value,... My nth Value"
I'd like to do some filtering on the table though, IE ensuring that there are no nulls and to ensure there are no duplicates. I was expecting something along the lines of:
SELECT dbo.MyFunction(SELECT DISTINCT myDate FROM myTable WHERE myDate IS NOT NULL)
You can, however no any table. From documentation:
For Transact-SQL functions, all data
types, including CLR user-defined
types and user-defined table types,
are allowed except the timestamp data
type.
You can use user-defined table types.
Example of user-defined table type:
CREATE TYPE TableType
AS TABLE (LocationName VARCHAR(50))
GO
DECLARE #myTable TableType
INSERT INTO #myTable(LocationName) VALUES('aaa')
SELECT * FROM #myTable
So what you can do is to define your table type, for example TableType and define the function which takes the parameter of this type. An example function:
CREATE FUNCTION Example( #TableName TableType READONLY)
RETURNS VARCHAR(50)
AS
BEGIN
DECLARE #name VARCHAR(50)
SELECT TOP 1 #name = LocationName FROM #TableName
RETURN #name
END
The parameter has to be READONLY. And example usage:
DECLARE #myTable TableType
INSERT INTO #myTable(LocationName) VALUES('aaa')
SELECT * FROM #myTable
SELECT dbo.Example(#myTable)
Depending on what you want achieve you can modify this code.
EDIT:
If you have a data in a table you may create a variable:
DECLARE #myTable TableType
And take data from your table to the variable
INSERT INTO #myTable(field_name)
SELECT field_name_2 FROM my_other_table
Unfortunately, there is no simple way in SQL Server 2005. Lukasz' answer is correct for SQL Server 2008 though and the feature is long overdue
Any solution would involve temp tables, or passing in xml/CSV and parsing in the UDF. Example: change to xml, parse in udf
DECLARE #psuedotable xml
SELECT
#psuedotable = ...
FROM
...
FOR XML ...
SELECT ... dbo.MyUDF (#psuedotable)
What do you want to do in the bigger picture though? There may be another way to do this...
Edit: Why not pass in the query as a string and use a stored proc with output parameter
Note: this is an untested bit of code, and you'd need to think about SQL injection etc. However, it also satisfies your "one column" requirement and should help you along
CREATE PROC dbo.ToCSV (
#MyQuery varchar(2000),
#CSVOut varchar(max)
)
AS
SET NOCOUNT ON
CREATE TABLE #foo (bar varchar(max))
INSERT #foo
EXEC (#MyQuery)
SELECT
#CSVOut = SUBSTRING(buzz, 2, 2000000000)
FROM
(
SELECT
bar -- maybe CAST(bar AS varchar(max))??
FROM
#foo
FOR XML PATH (',')
) fizz(buzz)
GO
Step 1: Create a Type as Table with name TableType that will accept a table having one varchar column
create type TableType
as table ([value] varchar(100) null)
Step 2: Create a function that will accept above declared TableType as Table-Valued Parameter and String Value as Separator
create function dbo.fn_get_string_with_delimeter (#table TableType readonly,#Separator varchar(5))
returns varchar(500)
As
begin
declare #return varchar(500)
set #return = stuff((select #Separator + value from #table for xml path('')),1,1,'')
return #return
end
Step 3: Pass table with one varchar column to the user-defined type TableType and ',' as separator in the function
select dbo.fn_get_string_with_delimeter(#tab, ',')
Cutting to the bottom line, you want a query like SELECT x FROM y to be passed into a function that returns the values as a comma separated string.
As has already been explained you can do this by creating a table type and passing a UDT into the function, but this needs a multi-line statement.
You can pass XML around without declaring a typed table, but this seems to need a xml variable which is still a multi-line statement i.e.
DECLARE #MyXML XML = (SELECT x FROM y FOR XML RAW);
SELECT Dbo.CreateCSV(#MyXml);
The "FOR XML RAW" makes the SQL give you it's result set as some xml.
But you can bypass the variable using Cast(... AS XML). Then it's just a matter of some XQuery and a little concatenation trick:
CREATE FUNCTION CreateCSV (#MyXML XML)
RETURNS VARCHAR(MAX)
BEGIN
DECLARE #listStr VARCHAR(MAX);
SELECT
#listStr =
COALESCE(#listStr+',' ,'') +
c.value('#Value[1]','nvarchar(max)')
FROM #myxml.nodes('/row') as T(c)
RETURN #listStr
END
GO
-- And you call it like this:
SELECT Dbo.CreateCSV(CAST(( SELECT x FROM y FOR XML RAW) AS XML));
-- Or a working example
SELECT Dbo.CreateCSV(CAST((
SELECT DISTINCT number AS Value
FROM master..spt_values
WHERE type = 'P'
AND number <= 20
FOR XML RAW) AS XML));
As long as you use FOR XML RAW all you need do is alias the column you want as Value, as this is hard coded in the function.
PASSING TABLE AS PARAMETER IN STORED PROCEDURE
Step 1:
CREATE TABLE [DBO].T_EMPLOYEES_DETAILS
(
Id int,
Name nvarchar(50),
Gender nvarchar(10),
Salary int
)
Step 2:
CREATE TYPE EmpInsertType AS TABLE
(
Id int,
Name nvarchar(50),
Gender nvarchar(10),
Salary int
)
Step 3:
/* Must add READONLY keyword at end of the variable */
CREATE PROC PRC_EmpInsertType
#EmployeeInsertType EmpInsertType READONLY
AS
BEGIN
INSERT INTO [DBO].T_EMPLOYEES_DETAILS
SELECT * FROM #EmployeeInsertType
END
Step 4:
DECLARE #EmployeeInsertType EmpInsertType
INSERT INTO #EmployeeInsertType VALUES(1,'John','Male',50000)
INSERT INTO #EmployeeInsertType VALUES(2,'Praveen','Male',60000)
INSERT INTO #EmployeeInsertType VALUES(3,'Chitra','Female',45000)
INSERT INTO #EmployeeInsertType VALUES(4,'Mathy','Female',6600)
INSERT INTO #EmployeeInsertType VALUES(5,'Sam','Male',50000)
EXEC PRC_EmpInsertType #EmployeeInsertType
=======================================
SELECT * FROM T_EMPLOYEES_DETAILS
OUTPUT
1 John Male 50000
2 Praveen Male 60000
3 Chitra Female 45000
4 Mathy Female 6600
5 Sam Male 50000
I've been dealing with a very similar problem and have been able to achieve what I was looking for, even though I'm using SQL Server 2000. I know it is an old question, but think its valid to post here the solution since there should be others like me that use old versions and still need help.
Here's the trick: SQL Server won't accept passing a table to a UDF, nor you can pass a T-SQL query so the function creates a temp table or even calls a stored procedure to do that. So, instead, I've created a reserved table, which I called xtList. This will hold the list of values (1 column, as needed) to work with.
CREATE TABLE [dbo].[xtList](
[List] [varchar](1000) NULL
) ON [PRIMARY]
Then, a stored procedure to populate the list. This is not strictly necessary, but I think is very usefull and best practice.
-- =============================================
-- Author: Zark Khullah
-- Create date: 20/06/2014
-- =============================================
CREATE PROCEDURE [dbo].[xpCreateList]
#ListQuery varchar(2000)
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM xtList
INSERT INTO xtList
EXEC(#ListQuery)
END
Now, just deal with the list in any way you want, using the xtList. You can use in a procedure (for executing several T-SQL commands), scalar functions (for retrieving several strings) or multi-statement table-valued functions (retrieves the strings but like it was inside a table, 1 string per row). For any of that, you'll need cursors:
DECLARE #Item varchar(100)
DECLARE cList CURSOR DYNAMIC
FOR (SELECT * FROM xtList WHERE List is not NULL)
OPEN cList
FETCH FIRST FROM cList INTO #Item
WHILE ##FETCH_STATUS = 0 BEGIN
<< desired action with values >>
FETCH NEXT FROM cList INTO #Item
END
CLOSE cList
DEALLOCATE cList
The desired action would be as follows, depending on which type of object created:
Stored procedures
-- =============================================
-- Author: Zark Khullah
-- Create date: 20/06/2014
-- =============================================
CREATE PROCEDURE [dbo].[xpProcreateExec]
(
#Cmd varchar(8000),
#ReplaceWith varchar(1000)
)
AS
BEGIN
DECLARE #Query varchar(8000)
<< cursor start >>
SET #Query = REPLACE(#Cmd,#ReplaceWith,#Item)
EXEC(#Query)
<< cursor end >>
END
/* EXAMPLES
(List A,B,C)
Query = 'SELECT x FROM table'
with EXEC xpProcreateExec(Query,'x') turns into
SELECT A FROM table
SELECT B FROM table
SELECT C FROM table
Cmd = 'EXEC procedure ''arg''' --whatchout for wrong quotes, since it executes as dynamic SQL
with EXEC xpProcreateExec(Cmd,'arg') turns into
EXEC procedure 'A'
EXEC procedure 'B'
EXEC procedure 'C'
*/
Scalar functions
-- =============================================
-- Author: Zark Khullah
-- Create date: 20/06/2014
-- =============================================
CREATE FUNCTION [dbo].[xfProcreateStr]
(
#OriginalText varchar(8000),
#ReplaceWith varchar(1000)
)
RETURNS varchar(8000)
AS
BEGIN
DECLARE #Result varchar(8000)
SET #Result = ''
<< cursor start >>
SET #Result = #Result + REPLACE(#OriginalText,#ReplaceWith,#Item) + char(13) + char(10)
<< cursor end >>
RETURN #Result
END
/* EXAMPLE
(List A,B,C)
Text = 'Access provided for user x'
with "SELECT dbo.xfProcreateStr(Text,'x')" turns into
'Access provided for user A
Access provided for user B
Access provided for user C'
*/
Multi-statement table-valued functions
-- =============================================
-- Author: Zark Khullah
-- Create date: 20/06/2014
-- =============================================
CREATE FUNCTION [dbo].[xfProcreateInRows]
(
#OriginalText varchar(8000),
#ReplaceWith varchar(1000)
)
RETURNS
#Texts TABLE
(
Text varchar(2000)
)
AS
BEGIN
<< cursor start >>
INSERT INTO #Texts VALUES(REPLACE(#OriginalText,#ReplaceWith,#Item))
<< cursor end >>
END
/* EXAMPLE
(List A,B,C)
Text = 'Access provided for user x'
with "SELECT * FROM dbo.xfProcreateInRow(Text,'x')" returns rows
'Access provided for user A'
'Access provided for user B'
'Access provided for user C'
*/
To obtain the column count on a table, use this:
select count(id) from syscolumns where id = object_id('tablename')
and to pass a table to a function, try XML as show here:
create function dbo.ReadXml (#xmlMatrix xml)
returns table
as
return
( select
t.value('./#Salary', 'integer') as Salary,
t.value('./#Age', 'integer') as Age
from #xmlMatrix.nodes('//row') x(t)
)
go
declare #source table
( Salary integer,
age tinyint
)
insert into #source
select 10000, 25 union all
select 15000, 27 union all
select 12000, 18 union all
select 15000, 36 union all
select 16000, 57 union all
select 17000, 44 union all
select 18000, 32 union all
select 19000, 56 union all
select 25000, 34 union all
select 7500, 29
--select * from #source
declare #functionArgument xml
select #functionArgument =
( select
Salary as [row/#Salary],
Age as [row/#Age]
from #source
for xml path('')
)
--select #functionArgument as [#functionArgument]
select * from readXml(#functionArgument)
/* -------- Sample Output: --------
Salary Age
----------- -----------
10000 25
15000 27
12000 18
15000 36
16000 57
17000 44
18000 32
19000 56
25000 34
7500 29
*/
create table Project (ProjectId int, Description varchar(50));
insert into Project values (1, 'Chase tail, change directions');
insert into Project values (2, 'ping-pong ball in clothes dryer');
create table ProjectResource (ProjectId int, ResourceId int, Name varchar(15));
insert into ProjectResource values (1, 1, 'Adam');
insert into ProjectResource values (1, 2, 'Kerry');
insert into ProjectResource values (1, 3, 'Tom');
insert into ProjectResource values (2, 4, 'David');
insert into ProjectResource values (2, 5, 'Jeff');
SELECT *,
(SELECT Name + ' ' AS [text()]
FROM ProjectResource pr
WHERE pr.ProjectId = p.ProjectId
FOR XML PATH (''))
AS ResourceList
FROM Project p
-- ProjectId Description ResourceList
-- 1 Chase tail, change directions Adam Kerry Tom
-- 2 ping-pong ball in clothes dryer David Jeff
The following will enable you to quickly remove the duplicate,null values and return only the valid one as list.
CREATE TABLE DuplicateTable (Col1 INT)
INSERT INTO DuplicateTable
SELECT 8
UNION ALL
SELECT 1--duplicate
UNION ALL
SELECT 2 --duplicate
UNION ALL
SELECT 1
UNION ALL
SELECT 3
UNION ALL
SELECT 4
UNION ALL
SELECT 5
UNION
SELECT NULL
GO
WITH CTE (COl1,DuplicateCount)
AS
(
SELECT COl1,
ROW_NUMBER() OVER(PARTITION BY COl1 ORDER BY Col1) AS DuplicateCount
FROM DuplicateTable
WHERE (col1 IS NOT NULL)
)
SELECT COl1
FROM CTE
WHERE DuplicateCount =1
GO
CTE are valid in SQL 2005 , you could then store the values in a temp table and use it with your function.
you can do something like this
/* CREATE USER DEFINED TABLE TYPE */
CREATE TYPE StateMaster AS TABLE
(
StateCode VARCHAR(2),
StateDescp VARCHAR(250)
)
GO
/*CREATE FUNCTION WHICH TAKES TABLE AS A PARAMETER */
CREATE FUNCTION TableValuedParameterExample(#TmpTable StateMaster READONLY)
RETURNS VARCHAR(250)
AS
BEGIN
DECLARE #StateDescp VARCHAR(250)
SELECT #StateDescp = StateDescp FROM #TmpTable
RETURN #StateDescp
END
GO
/*CREATE STORED PROCEDURE WHICH TAKES TABLE AS A PARAMETER */
CREATE PROCEDURE TableValuedParameterExample_SP
(
#TmpTable StateMaster READONLY
)
AS
BEGIN
INSERT INTO StateMst
SELECT * FROM #TmpTable
END
GO
BEGIN
/* DECLARE VARIABLE OF TABLE USER DEFINED TYPE */
DECLARE #MyTable StateMaster
/* INSERT DATA INTO TABLE TYPE */
INSERT INTO #MyTable VALUES('11','AndhraPradesh')
INSERT INTO #MyTable VALUES('12','Assam')
/* EXECUTE STORED PROCEDURE */
EXEC TableValuedParameterExample_SP #MyTable
GO
For more details check this link: http://sailajareddy-technical.blogspot.in/2012/09/passing-table-valued-parameter-to.html