I am sure the answer is NO, but I'll ask the expert anyway ;)
I've declared a table variable in my stored procedure.
DECLARE #OrderMapIds TABLE
(
OrderId INT NOT NULL,
NewOrderId INT NOT NULL
);
INSERT INTO #OrderMapIds (OrderId, NewOrderId)
SELECT [OrderId], [OrderId] FROM [tblOrder]
...
...
...
EXEC [AS.uspOrder_MoveOrder] #OrderMapIds = #OrderMapIds; --I need to move order ids based on the mapped id
I need to pass #OrderMapIds to [AS.uspOrder_MoveOrder]. The question is how?
CREATE PROCEDURE [AS.uspOrderItem_CopyRecord]
(
#OrderMapIds AS TABLE -- This thrown error
)
AS
BEGIN
...
...
...
END;
Now, I can accomplish this problem using Table-Valued Parameter (TVP). But if I could pass it without TVP, then it will be better (so I don't have to create TVP for small stuff).
Now, after looking at Google, I am sure the answer is NO (ie. I need to create TVP to accomplish task above). But I thought to ask the question in hope I might have missed something.
Any help is greatly appreciated.
Thanks
You are correct. The answer is indeed No.
In SQL Server, the only way to pass a table to a stored procedure is using a user defined table type.
You do have some confusion in the terms, though.
TVP is the parameter itself - so even if you could just pass any table variable a stored procedure - it would still be a Table Valued Parameter.
What you want to avoid (but can't) is a User Defined Table Type.
If this was allowed, you would end up with a stored procedure that takes in a table valued parameter with an unknown structure - And this could lead to errors, extremely cumbersome code, and worst of all - silently using the wrong data.
An interesting alternative, especially when the table structure is variable/dependent will be to convert data as JSON/XML ( data type for parameter will be NVARCHAR).
Way to go in your example will be
DECLARE #OrderMapIds NVARCHAR(MAX)=
(
SELECT [OrderId], [OrderId] FROM [tblOrder] FOR JSON PATH
);
...
...
...
EXEC [AS.uspOrder_MoveOrder] #OrderMapIds = #OrderMapIds;
Related
I have 2 tables
Account(AccountId, Encoding)
DeviceAccountMap(AccountId, DeviceId)
Now I need to fetch the devices from the DeviceAccountMap. I pass a list of AccountId to a stored procedure and while fetching the DeviceId from the DeviceAccountMap table I need to compare the Encoding value for each account with a particular value.
Which is the easy way to do this? I am totally lost.
The select clause in the stored procedure will look something like this:
DECLARE #Accounts [usp].[Array]
and [usp].[Array] is defined as below
CREATE TYPE [usp].[Array] AS TABLE
(
Value VARCHAR(36) NULL
)
SELECT
DeviceId,
AccountEncoding = A.Encoding
FROM
usp.DeviceControllerAccountMap DCAM
INNER JOIN
usp.Account A ON (DCAM.AccountId = A.AccountId)
WHERE
DCAM.AccountId IN (SELECT Value From #AccountIds)
AND DCAM.IsShared = 1
AND AccountEncoding LIKE A.Encoding + '.%'
In other words I need to fetch the encoding value for each account and use that in this where clause.
So you can look up information on Table-Valued Parameters (TVPs) in T-SQL.
Here is an article by Erland Sommarskog.
You can refer to this StackOverflow answer to see an example of C# code calling a stored procedure that uses a TVP. I believe TVPs require SQL Server 2008 or higher.
TVPs, as far as I understand, provide a way to make your own data type in sql server that gets treated as if it was a table. You're doing this when you declare your Array type and then when you use the #AccountIds in your stored procedure's select statement.
CREATE TYPE [usp].[Array] AS TABLE -- maybe choose a more descriptive name than 'Array'
(
Value VARCHAR(36) NULL -- choose a more descriptive name than 'Value'
)
CREATE PROCEDURE [usp].[your_procedure_name]
#AccountIds [usp].[Array] READONLY -- use TVP as a parameter
AS
SELECT …
It is not clear form your question details whether you also mean to have a parameter in the stored procedure for the Encoding. It seems like you're looking for accounts whose Encodings start with a period '.'.
So first, create your type, like you're doing.
Then create your stored procedure.
Then test your stored procedure, something like this:
DECLARE #mylist Array -- make TVP sample data
INSERT #mylist(Value) VALUES(1),(11),(27),(123) -- insert some values
exec your_procedure_name #mylist -- run stored procedure
The following line is completely unnecessary. The JOIN to Account does this filter for you.
DCAM.AccountId IN (SELECT Value From #AccountIds)
Or am I missing something?
I am using a stored procedure to insert records into a table. And do this at least 12 times in a loop to insert multiple records which is very inefficient.
here is the procedure as CREATED
Create PROC [dbo].[SP_INSERT_G_SAMPLING]
#GameID INT,
#ScoreID INT
as
begin
INSERT INTO GAMESCORE (GAMEID, SCOREID) VALUES
(#GameID, #ScoreID)
end
I pass on the values ex(1,3) and loop with more values from the website.
I want to however pass on all the values at one time like (1,3),(4,5),(8,9)
and then alter the above procedure to receive and insert multiple rows.
ALTER PROC [dbo].[SP_INSERT_G_SAMPLING]
#totalinsert nvarchar(Max)
INSERT INTO GAMESCORE (GAMEID, SCOREID) VALUES
(#totalinsert)
with #totalinsert being like (1,3),(4,5),(8,9) pushed from the webpage.
any help is greatly appreciated
What you're going to have to do is write a table valued function which accepts the multi-value string and breaks it out into a table object. If you can change your source to use a record delimiter instead of having comma sets it would be slightly easier to process. An example of that would look like this.
The below is pure psuedo and has not been validated in any way, just meant to give you a rough idea of where to go.
ex: #TotalInsert = 1,2|4,5|8,9
DECLARE #Results TABLE
(
value1 INT,
value2 INT
)
DECLARE #setlist VARCHAR(max);
WHILE Len(#TotalInsert) > 0
BEGIN
SET #setlist = LEFT(#totalinsert, Charindex('|', #totalinsert))
INSERT INTO #results
SELECT LEFT(#setlist, Charindex(',', #setlist) - 1),
RIGHT(#setlist, Charindex(',', Reverse(#setlist)) + 1)
SET #totalinsert = RIGHT(#totalinsert, Len(#totalinsert) - Len(#setlist))
END
I'm assuming you're using .NET for your website since you're also using SQL Server.
Have a look at table valued parameters, this page also includes a nice example of how to use the table valued parameters in .NET.
Check here for a better example of making a stored procedure with a table valued parameter in T-SQL.
Here is the full discussion:
http://www.sommarskog.se/arrays-in-sql-2005.html#XMLlist%20of%20values
Personally, I sent xml to the stored procedure, I "shred it" into #variable or #temp tables, then I do my INSERT/UPDATE/MERGE/DELETE from there.
Here is a fuller discussion on xml-shredding.
http://pratchev.blogspot.com/2007/06/shredding-xml-in-sql-server-2005.html
My personal trick is to create a strong dataset, populate the strong dataset with rows, and use the ds.GetXml() to send the xml down to the TSQL. With a strong dataset, I get strong-typing when populating the values. But at the end of the day, dataset is just some super fancy xml.
First of all, thank you guys. You always know how to direct me when I can't even find the words to explain what the heck I'm trying to do.
The default values of the columns on a couple of my tables need to be equal the result of some complicated calculations on other columns in other tables. My first thought is to simply have the column default value equal the result of a stored procedure. I would also have one or more of the parameters pulled from the columns in the calling table.
I don't know the syntax of how to do it though, and any time the word "stored" and "procedure" land next to each other in google I'm flooded with info on Parameter default values and nothing relating to what I actually want.
Half of that was more of a vent than a question...any ideas though? And plz plz don't say "Well, you could use an On-Insert Trigger to..."
You can't have the default be the result of a stored procedure, it has to be a function. If you can convert the procedure into a function, then you can use that function. If you cannot, then you must use a trigger.
You would have to convert that stored procedure to a user-defined function. There are different types of UDF's - the one you're looking at would be the scalar UDF - returning a single value.
So for instance you could create a function like this:
CREATE FUNCTION dbo.YourDefaultFunction(#Input1 INT, #Input2 VARCHAR(10))
RETURNS VARCHAR(100)
AS BEGIN
DECLARE #Result VARCHAR(100)
SET #Result = #Input2 + ' - giving: ' + CAST(#Input1 AS VARCHAR(5))
RETURN #Result
END
Of course, yours would be a lot more complicated :-)
Once you've done that, you can define this to be the default for a column of type VARCHAR(100) - either directly when declaring the table, or later on via an ALTER TABLE statement:
CREATE TABLE dbo.YourTable(.......
SomeColumn VARCHAR(100)
CONSTRAINT DF_YourTable_SomeColumn
DEFAULT (dbo.YourDefaultFunction(417, 'Test')),
.....)
or :
ALTER TABLE dbo.YourTable
ADD CONSTRAINT DF_YourTable_SomeColumn
DEFAULT (dbo.YourDefaultFunction(4711, 'Test2'))
FOR SomeColumn
Unfortunately, you cannot pass other columns as parameters to your function when defining it as a default value for a column.
Does that help??
I would like to create a SP or UDF where I supply a table and column name as a parameter and it does something to that target. I'm using Sql Server 2005
Trivial Example of what I'm trying to accomplish:
CREATE FUNCTION Example (#TableName AS VARCHAR(100))
RETURNS TABLE
AS
BEGIN
SELECT *
INTO #temp
FROM #TableName
RETURN #temp
END
The example is just something trivial to illustrate what I'm trying to accomplish in terms of passing the Table name as a parameter.
Is this possible to do w/o concatinating strings and calling the EXEC function?
Ultimately, I'm trying to convert the answer from this question into something reusable.
This reeks of SQL injection. You would still need to use EXEC to do this.
No. Can't do it. Sadly, there is no macro pre-complier in T-SQL. The closest you'll get is SQLCMD mode, but that's only for scripts, can't use it in object definitions.
Are you doing the same thing to the table each time?
You could dynamically redefine a synonym, but that still requires an EXEC and you lose concurrency. You could serialize execution with a queue, but at that point you may be better off w/ plain old dynamic SQL.
You might try temporary tables, not passed in as a variable, but created in the parent connection or calling procedure. eg.
create proc #proc as
select * from #table
go
create table #table (col1 int)
insert #table values (1)
insert #table values (2)
insert #table values (3)
go
exec #proc
go
For more ways to share data between stored procedures, see here: http://www.sommarskog.se/share_data.html
I am executing a SP within a SP. The SP returns say 10 params. I am interested in only 5 of them. How do I insert only these 5 into the temp table.
The code I have so far:
DECLARE #tmpUnion TABLE
(
UnionCode VARCHAR(10),
UnionDate DATETIME,
UnionPosition VARCHAR(30),
UnionInitFees BIT,
UnionDues BIT
)
--getDetails returns 10 params. I need only these 5
INSERT INTO #tmpUnion
(UnionCode, UnionDate, UnionPosition, UnionInitFees, UnionDues)
EXEC getDetails
#iUserId = #OriginalLoginId
Put the result of getDetails into a tablevar that contains all of the return values, then do your insert off of the additional table.
You might also check out this site for more information on how to share data between stored procedures.
Use OPENROWSET like so:
Select
*
from OPENROWSET('SQLOLEDB','Data Source=Server_name;Trusted_Connection=yes;
Integrated Security=SSPI','Execute yourdb..get_orders')
Now you can easily filter the resultset
Select
employeeid,orderid,orderdate
from
OPENROWSET('SQLOLEDB','Data Source=Server_name;Trusted_Connection=yes;
Integrated Security=SSPI','Execute yourdb..get_orders')
where
orderdate>='19960101' and orderdate<'19970101'
You don't need to create a temp table and you also don't need to worry about the structure of the procedure.
Found here
EDIT: Final solution moved from comments after discussion.
You can't. The table variable must match exactly the structure of waht is being returned.