UPDATE users
SET field = my_sp()
in SQL Server 2005. Apparently I can't do this and have to use some form of EXEC. Can anyone help me out and let me know how to do this? This should be some easy rep.
To assign value you need to use sql function. it is impossible to assign value from stored procedure.
Here is link how to create it.
you need to write a scalar function that takes some parameters (or even zero) and returns what you need.
You could store the output of the stored procedure in a temp table, then use that temp table as the basis for your update. As an example, the code below assumes your proc returns a record set with two integers.
create table #t (
ColumnA int,
ColumnB int
)
insert into #t
(ColumnA, ColumnB)
exec my_sp
update u
set field = t.ColumnB
from users u
inner join #t t
on u.UserID = t.ColumnA
drop table #t
Related
I'm not sure if this is something I should do in T-SQL or not, and I'm pretty sure using the word 'iterate' was wrong in this context, since you should never iterate anything in sql. It should be a set based operation, correct? Anyway, here's the scenario:
I have a stored proc that returns many uniqueidentifiers (single column results). These ids are the primary keys of records in a another table. I need to set a flag on all the corresponding records in that table.
How do I do this without the use of cursors? Should be an easy one for you sql gurus!
This may not be the most efficient, but I would create a temp table to hold the results of the stored proc and then use that in a join against the target table. For example:
CREATE TABLE #t (uniqueid int)
INSERT INTO #t EXEC p_YourStoredProc
UPDATE TargetTable
SET a.FlagColumn = 1
FROM TargetTable a JOIN #t b
ON a.uniqueid = b.uniqueid
DROP TABLE #t
You could also change your stored proc to a user-defined function that returns a table with your uniqueidentifiers. You can joing directly to the UDF and treat it like a table which avoids having to create the extra temp table explicitly. Also, you can pass parameters into the function as you're calling it, making this a very flexible solution.
CREATE FUNCTION dbo.udfGetUniqueIDs
()
RETURNS TABLE
AS
RETURN
(
SELECT uniqueid FROM dbo.SomeWhere
)
GO
UPDATE dbo.TargetTable
SET a.FlagColumn = 1
FROM dbo.TargetTable a INNER JOIN dbo.udfGetUniqueIDs() b
ON a.uniqueid = b.uniqueid
Edit:
This will work on SQL Server 2000 and up...
Insert the results of the stored proc into a temporary table and join this to the table you want to update:
INSERT INTO #WorkTable
EXEC usp_WorkResults
UPDATE DataTable
SET Flag = Whatever
FROM DataTable
INNER JOIN #WorkTable
ON DataTable.Ket = #WorkTable.Key
If you upgrade to SQL 2008 then you can pass table parameters I believe. Otherwise, you're stuck with a global temporary table or creating a permanent table that includes a column for some sort of process ID to identify which call to the stored procedure is relevant.
How much room do you have in changing the stored procedure that generates the IDs? You could add code in there to handle it or have a parameter that lets you optionally flag the rows when it is called.
Use temporary tables or a table variable (you are using SS2005).
Although, that's not nest-able - if a stored proc uses that method then you can't dumpt that output into a temp table.
An ugly solution would be to have your procedure return the "next" id each time it is called by using the other table (or some flag on the existing table) to filter out the rows that it has already returned
You can use a temp table or table variable with an additional column:
DECLARE #MyTable TABLE (
Column1 uniqueidentifer,
...,
Checked bit
)
INSERT INTO #MyTable
SELECT [...], 0 FROM MyTable WHERE [...]
DECLARE #Continue bit
SET #Continue = 1
WHILE (#Continue)
BEGIN
SELECT #var1 = Column1,
#var2 = Column2,
...
FROM #MyTable
WHERE Checked = 1
IF #var1 IS NULL
SET #Continue = 0
ELSE
BEGIN
...
UPDATE #MyTable SET Checked = 1 WHERE Column1 = #var1
END
END
Edit: Actually, in your situation a join will be better; the code above is a cursorless iteration, which is overkill for your situation.
I'm looking for some views on how to go about resolving this challenge. I have a variable say #Var1 which holds a SQL statement within it.
Example
#Var1 = `SELECT * from another_table WHERE City IS NOT NULL AND Address IS NOT NULL`
When I execute this variable
EXECUTE sp_executesql #Var1
I get the desired result, City and Address excluding NULL values.
I am hoping to update a existing table (tbl1) based on execution result of #Var1:
Something like:
UPDATE TABLE tbl1 AS (EXECUTE sp_executesql #Var1)
Is something like this even possible? Or what approach can I take to get the result of #Var1 into tbl1?
Thanks in advance.
My apologies for including links for each step but they deserve the credit.
There are 2 steps. Insert into a temp-table then merge the data from that temp-table into your final table.
You will have to insert into a Temp Table first.
INSERT INTO #TABLE EXEC #query with SQL Server 2000
Then you have to merge that data into you main table.
SQL MERGE statement to update data
try This
UPDATE tbl1
SET Column1= b.Column1,
SET Column2= b.Column2,
SET Column3= b.Column3,
FROM tbl1 a
INNER JOIN (
SELECT Column1,Column2,Column3
FROM another_table WHERE City IS NOT NULL AND Address IS NOT NULL ) b ON a.city_Id = b.city_Id
I am operating on a MSSQL 2005 database system that has many stored procedures. One of the stored procedures is a "report" and I want to sort it without editing the stored procedure. Is there a way to sort the results of a stored procedure on the fly : something like this:
exec spReport
order by ColumnT
You can insert into a temporary table. Then, sort from table.
e.g.
INSERT INTO #table
EXEC spReport
SELECT *
FROM #table
ORDER BY ColumnT
No, you cannot do this. If you know the structure of the resultset, you can build a #tmp table first, insert #tmp exec spReport, then select from the #tmp table with an order by clause. You may even be able to hack something together using OPENQUERY or OPENROWSET, but I would recommend editing spReport either to always use the order you want or to take a parameter and define the order based on the parameter.
You should fill a temporary table with the result and then sort it. Here is the link showing how to do the first part:
How to SELECT * INTO temp table FROM Stored Procedure
Can I join a table with a Stored Procedure which returns a table ?
Thanks
You need to use INSERT.. EXEC to store the data from the SP into a table or table-variable. Then you can join to that.
Say the SP returns a table (a int, b varchar(10), c datetime)
declare #temp table (a int, b varchar(10), c datetime)
;
insert #temp
exec myproc 1, 10, 'abcdef'
;
select *
from #temp t join othertable o on ... etc
Without creating a temp table, if you also exclude table-variable, then the only option - provided the SP -does not take any- parameters, is to use OPENQUERY to run the SP to return a table. Pseudo:
select *
from OPENQUERY(local_server, 'spname_no_params') t
join othertable o on ... etc
You can't join directly onto a stored procedure. So you either need to use the approach per Richard's answer, or you could convert the sproc to a table valued function.
e.g.
CREATE FUNCTION dbo.fxnExample(#Something INTEGER)
RETURNS TABLE
AS
RETURN
(
SELECT A, B
FROM MyTable
WHERE Something = #Something
)
which you then use/JOIN on in a query like this:
SELECT t1.Foo, f.A, f.B
FROM Table1 t1
JOIN dbo.fxnExample(1) f ON t1.A = f.A
The thing to note is you can't do everything in a user defined function that you can in a sproc so depending on what your sproc does, this may not be possible. Also, for best performance you should make it an inline table valued function like my example above. The alternative is a multi-statement table valued function which could give you poor performance due to the way that the execution plan produced will be based on an assumption of a very low number of rows being returned by it (i.e. 1) - so if it returned a larger number of rows then performance could be poor.
Here's a good MSDN article on it: http://blogs.msdn.com/b/psssql/archive/2010/10/28/query-performance-and-multi-statement-table-valued-functions.aspx
No it's not possible. What you can do is put the output of that SP into a temporary table and use it to your join statement.
I have a SP that calls another SP and the resultset needs to be filtered to only the columns that I am interested in.
DECLARE #myTable TABLE
(
Field1 INT,
Field2 INT,
Field3 INT
)
--If someSP returns say 30 params and I need only 3 params, I don't want to declare all 30 in my temp table #myTable
INSERT INTO #myTable
(Field1, Field2, Field3)
EXEC someSP --Need to selectively filter recordset from SP
#InputParam1 = 'test'
If I cannot do this, I would want to create the temp table DYNAMICALLY based on the resultset from someSP (This way it relieves maintenance issues when someSP is modified to add a new param, I dont need to modify this proc as well
Short answer: no, you can't do that.
You have to pre-declare your temp table with the exact number of columns that will be returned from the stored proc.
The workaround is to use persistent tables. For example, you could have a permanent table in your database called someSPResults. Whenever someSP is changed to have a different number of output columns, change the format of someSPResults as part of the deployment.
Then you can either do this:
insert into dbo.someSPresults
exec someSP
Or inside someSP, you can have the results be inserted directly into the someSPresults table as a normal part of execution. You just have to make sure to identify exactly which records in the someSPresults table came from each execution of someSP, because that stored proc could be fired multiple times simultaneously, thereby dumping a lot of data into someSPresults.
cmsjr stated, "A table variable cannot be the target of a result set from another stored procedure."
I thought that was true too, but then I tested it. This code works in both 2005 and 2008:
CREATE PROCEDURE someSP (#InputParam1 varchar(100)) AS
SELECT LEN(#InputParam1), DATALENGTH(#InputParam1), ##SPID
GO
DECLARE #myTable TABLE (
Field1 INT,
Field2 INT,
Field3 INT
)
INSERT INTO #myTable (Field1, Field2, Field3)
EXEC someSP
#InputParam1 = 'test'
SELECT * FROM #myTable
I knew that would work with #temp tables, but I thought it would not work with #temp tables.
That doesn't answer DotnetDude's question though.
A table variable cannot be the target of a result set from another stored procedure, also you can't perform DDL on table variables after they are declared, they will always have the same definition they were declared with. Temp table is your best bet.
I could think of two options, but I didn't have time to test them: convert the SP into an User Defined Function and use the SELECT * FROM {function} INTO {table}, or use OPENROWSET:
SELECT *
FROM OPENROWSET('SQLOLEDB',
'servername';'username';'password',
'exec dbname.{owner}.yourstoredproc') AS spResult
INTO {tablename}
Both solutions should create the table on the fly, then you can simply select from it.
Based on the comments above, I'd suggest you consider a table valued function.
This can be parameterised and you can do this:
INSERT #foo (col1, col14, col29)
SELECT col1, col14, col29 FROM dbo.ufnTVF (#p1, #p2)
Otherwise, it's OPENROWSET as the "cleanest" (I use this loosely) solution
Or, you modify the resultset of your stored proc to onlky return the columns you want.
This implies dynamic SQL or lots of IF statements. Which in some circumstances will not parse correctly (with SET FMTONLY etc).
You could be trying to code against a 3rd party app or system stored procs (we don't have full details), but it feels messy and wrong. SQL Server 2005 has a huge number of DMVs and catalogue (or catalog depending on which side of the Atlantic you are) views that remove the need for system proc calls.
If you're trying to mimic some aspects of OO design (one proc to do something for everyboy), then I wouldn't. If you need a query that retruns 3 columns of 30, then do so. This will run far better because unused tables and columns will be ignored on in the plan, indeed do not need included.