Replace redundant Code with SP / UDF - sql-server

I have code:
SELECT Date
,trafficsource
INTO #temp
FROM SomeTable;
That is the first step. The second step is the following code:
INSERT INTO dbo.DimTrafficSource ( TrafficSource, LogInsert )
SELECT DISTINCT fact.trafficSource
,GETDATE()
FROM #temp fact
LEFT JOIN dbo.DimTrafficSource dim ON fact.trafficSource = dim.TrafficSource
WHERE dim.TrafficSource IS NULL
Now, the second step is used in many other stored procedures. To avoid using the same "hardcoded" code in them, I'd prefer to replace this functionality with other function / stored procedure so when I want to modify the logic, I want to modify it at one place, not in every stored procedure using this code. Is it possible when there is a temp table used? How?

Yes you can. If you switch from a local to a global temp table (## instead of #) it will be available to all SPs you create. The example below demonstrates this.
However I would recommend you switch to regular table. Temp tables can be hard to debug and track. It is not always obvious when they do/don't exist.
Example
/* Temp procedure 1 creates a
* global temp table.
*/
CREATE PROCEDURE #Temp1 AS
BEGIN
SELECT
1 AS x
INTO
##tempT
;
END
GO
/* Temp procedure 2
* can access the temp table..
*/
CREATE PROCEDURE #Temp2 AS
BEGIN
SELECT
x
FROM
##tempT
;
END
GO
/* Excecuting the SPs
* show the temp table is shared.
*/
EXECUTE #Temp1;
EXECUTE #Temp2;

Related

Stored procedure that creates #table - unable to find it in list of tables

I'm trying to run a stored procedure that creates a local table - #table1
The stored procedure is supposed to look for values and create the table and insert the values into it...
INSERT INTO #table1
I execute the stored procedure and it shows that 1 row() affected, however, I am unable to find this table in the list of my tables. Why am I not able to see it or access it?
EDIT: I'm running the stored procedure inside SQL Server against a database. At the end of the stored procedure, the last line is:
Select * from #table1
Thanks.
The #table is a local temp table. It does not exist as a permanent table that you can look for outside the scope of the stored proc. Once the stored proc is run, the temp table is dropped because it is no longer in scope. Temp tables are stored temporarily in the tempdb database but with a different name because two people running the stored procedure at the same time would each have a table that can be referenced in the proc as #table but it would be two separate tables in the tempdb.
Now if what you are doing is looking to see what is in #table at a point in the stored proc in order to troubleshoot the proc, then you need to set thing up in the proc so that you can see the results at different stages or when you hit a certain state such as an error.
This could be something like adding a #debug variable to the proc so that when you are in debug mode, you can select the results to the screen when you are running something like:
CREATE PROC test_proc (#Id INT, #debug BIT = 0)
AS
CREATE TABLE #temp(id INT)
INSERT INTO #temp
VALUES (#Id), (1), (2)
IF #debug = 1
BEGIN
SELECT * FROM #temp
END
UPDATE #temp
SET Id = id-1
IF #debug = 1
BEGIN
SELECT * FROM #temp
END
GO
You would then execute the proc without debugging as so (note that since I am not returning something or inserting to permanent tables, this proc will insert to #temp but you can't see anything. I just didn't want to get complicated here, the steps of the proc will vary depending on what you want to do, the concept I am trying to show is how to use the debug variable):
EXEC test_proc #Id= 5
and with debugging as
EXEC test_proc #Id= 5, #debug= 1
Or it might involved using a table variable instead (because they don't get rolled back on error) and then inserting the data from that table variable into a logging table after the rollback occurs in the Catch block, so that you can see the values at the time the error occurred.
Without knowing more about why you are looking for #temp and what the data means and is used for, it is hard to say what you need to do.
Did you tried refreshing the tables after exceuting Stored procedure

How to access Temp Table in the stored procedure which is created in another stored procedure? [duplicate]

This question already has answers here:
How to pass a temp table as a parameter into a separate stored procedure
(3 answers)
Closed 9 months ago.
I had an interview in which interviewer asked me a question that how can you access temp table in the stored procedure which is created in another stored procedure and that procedure does not drop temp table?
I answered him that you can access the temp table in a same session. He said but when you will do this:
Select * from #table
It will give an error because #table is not created in current SP. I said that you can access temp table in a same session and if both SP's are in same session then you can access that temp table. I did not try this but there will be some way to access it. He said yes you can access it but how? Try it at home.
I know that table created with #table is a temp table. It is only accessible in a same session. I am trying to access temp table created by other sp in a same session but i am unable to access it. Is there any way to do this?
Building on Damien comments..
The table can be referenced by any nested stored procedures executed by the stored procedure that created the table
create proc usp_innertest1
as
begin
select n as innertest1 from #test
end
create proc usp_innertest2
as
begin
select n as innertest2 from #test
end
create proc dbo.test
as
begin
select top 1* into #test from numbers
exec usp_innertest1
exec usp_innertest2
end
now Executing test gives
innertest1
1
innertest2
1
The table cannot be referenced by the process which called the stored procedure that created the table
this is obvious,if usp_innertest1 creates a temp table,it can't be accessed by test(main calling process)
There are also global temporary tables which reside till all the references are closed
---connection1
select top 1 * into ##test from numbers
--now open new connection(connection 2) and do below
begin tran
update ##test
set id=1
--now close connection1
-- now go to connection 2
select * from ##test
you can access this table until you committed it
commit
you have to call the store procedure in which you want to use this temp table from the one which creates this temp table.
If you want to use for global the temp table like...
select Email='temp#sample.com',[Name]='TemplName'
into ##testTempTable
in another scope even in view or stor procedure, use to select possible columns like..
select *from ##testTempTable
select distinct object_name(id)
from syscomments
where text like '%#tmp_table_name%'
order by object_name(id)
This will return a list of any stored procedures that use that specific text of the temp table

TSQL: use global ##temp for multiple runs of same sp, how to reuse?

I have to run same sp with 100 diff #params once a month which reference data which is hard to get (view runs 2 min, and I need only 2% subset from this view). I want to create some ##temp table so then my sp in all instances will refer to it. How people do this on tsql arena?
Can I include:
If exist then do nothing
in the top of sp code, so it will run only once? and then delete table in separate clean job. or do some ##temp tables, I"m bit new to this . not sure will ## global temp table will work. ALso do I need to go with some special Isolation Level (Serial?) to do this.
Tx for help.
Mario
If the procedure only runs once a month, and view takes its time to run (expensive query) why not just create a table (maybe create some indexes too , to aid the following queries) and then finally create another procedure to populate that table each time you execute your original procedure.
-- Create a holding table
SELECT * INTO Holding_Table
FROM Your_View
WHERE 1 = 2
-- Procedure to populate data into that holding table
CREATE PROCEDURE populate_data
AS
BEGIN
TRUNCATE TABLE Holding_Table
INSERT INTO Holding_Table
SELECT * FROM Your_View
END
Now call this procedure from your existing procedure to populate the data and carry on working with the holding table as usual ...
ALTER PROCEDURE your_existing_Proc
AS
BEGIN
Exec populate_data
..... rest of the procedure definition

nested insert exec work around

I have 2 stored procedures usp_SP1 and usp_SP2. Both of them make use of insert into #tt exec sp_somesp. I wanted to create a 3rd stored procedure which will decide which stored proc to call. Something like:
create proc usp_Decision
(
#value int
)
as
begin
if (#value = 1)
exec usp_SP1 -- this proc already has insert into #tt exec usp_somestoredproc
else
exec usp_SP2 -- this proc too has insert into #tt exec usp_somestoredproc
end
Later, I realized I needed some structure defined for the return value from usp_Decision so that I can populate the SSRS dataset field. So here is what I tried:
Within usp_Decision created a temp table and tried to do "insert into #tt exec usp_SP1". This didn't work out. error "insert exec cannot be nested"
Within usp_Decision tried passing table variable to each of the stored proc and update the table within the stored procs and do "select * from ". That didn't work out as well. Table variable passed as parameter cannot be modified within the stored proc.
Please suggest what can be done.
Can you modify usp_SP1 and usp_SP2?
If so, in usp_Decision, create a local temporary table with the proper schema to insert the results:
create table #results (....)
Then, in the called procedure, test for the existence of this temporary table. If it exists, insert into the temporary table. If not, return the result set as usual. This helps preserve existing behavior, if the nested procedures are called from elsewhere.
if object_id('tempdb..#results') is not null begin
insert #results (....)
select .....
end
else begin
select ....
end
When control returns to the calling procedure, #results will have been populated by the nested proc, whichever one was called.
If the result sets don't share the same schema, you may need to create two temporary tables in usp_Decision.
Have you had a look at table-valued user-defined functions (either inline or multi-statement)? Similar to HLGEM's suggestion, this will return a set which you may not have to insert any where.
Not a fan of global temp tables in any event (other processes can read these table and may interfere with the data in them).
Why not have each proc use a local temp table and select * from that table as the last step.
Then you can insert into a local temp table in the calling proc.
esimple example
create proc usp_mytest1
as
select top 1 id into #test1
from MYDATABASE..MYTABLE (nolock)
select * from #test1
go
--drop table #test
create proc usp_mytest2
as
select top 10 MYTABLE_id into #test2
from MYDATABASE..MYTABLE (nolock)
select * from #test2
go
create proc usp_mytest3 (#myvalue int)
as
create table #test3 (MYTABLE_id int)
if #myvalue = 1
Begin
insert #test3
exec ap2work..usp_mytest1
end
else
begin
insert #test3
exec ap2work..usp_mytest2
end
select * from #test3
go
exec ap2work..usp_mytest3 1
exec ap2work..usp_mytest3 0
See this blog article for one wortkaround (uses OPENROWSET to essentially create a loopback connection on which one of the INSERT EXEC calls happens)

How to return temporary table from stored procedure

CREATE PROCEDURE [test].[proc]
#ConfiguredContentId int,
#NumberOfGames int
AS
BEGIN
SET NOCOUNT ON
RETURN
#WunNumbers TABLE (WinNumb int)
INSERT INTO #WunNumbers (WinNumb)
SELECT TOP (#NumberOfGames) WinningNumber
FROM [Game].[Game] g
JOIN [Game].[RouletteResult] AS rr ON g.[Id] = rr.[gameId]
WHERE g.[ConfiguredContentId] = #ConfiguredContentId
ORDER BY g.[Stoptime] DESC
SELECT WinNumb, COUNT (WinNumb) AS "Count"
FROM #WunNumbers wn
GROUP BY wn.[WinNumb]
END
GO
This stored procedure returns values from first select statement, but I would like to have values from second select statement to be returned. Table #WunNumbers is a temporary table.
Any ideas???
Take a look at this code,
CREATE PROCEDURE Test
AS
DECLARE #tab table (no int, name varchar(30))
insert #tab select eno,ename from emp
select * from #tab
RETURN
What version of SQL Server are you using? In SQL Server 2008 you can use Table Parameters and Table Types.
An alternative approach is to return a table variable from a user defined function but I am not a big fan of this method.
You can find an example here
A temp table can be created in the caller and then populated from the called SP.
create table #GetValuesOutputTable(
...
);
exec GetValues; -- populates #GetValuesOutputTable
select * from #GetValuesOutputTable;
Some advantages of this approach over the "insert exec" is that it can be nested and that it can be used as input or output.
Some disadvantages are that the "argument" is not public, the table creation exists within each caller, and that the name of the table could collide with other temp objects. It helps when the temp table name closely matches the SP name and follows some convention.
Taking it a bit farther, for output only temp tables, the insert-exec approach and the temp table approach can be supported simultaneously by the called SP. This doesn't help too much for chaining SP's because the table still need to be defined in the caller but can help to simplify testing from the cmd line or when calling externally.
-- The "called" SP
declare
#returnAsSelect bit = 0;
if object_id('tempdb..#GetValuesOutputTable') is null
begin
set #returnAsSelect = 1;
create table #GetValuesOutputTable(
...
);
end
-- populate the table
if #returnAsSelect = 1
select * from #GetValuesOutputTable;
YES YOU CAN.
In your stored procedure, you fill the table #tbRetour.
At the very end of your stored procedure, you write:
SELECT * FROM #tbRetour
To execute the stored procedure, you write:
USE [...]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[getEnregistrementWithDetails]
#id_enregistrement_entete = '(guid)'
GO
The return type of a procedure is int.
You can also return result sets (as your code currently does) (okay, you can also send messages, which are strings)
Those are the only "returns" you can make. Whilst you can add table-valued parameters to a procedure (see BOL), they're input only.
Edit:
(Or as another poster mentioned, you could also use a Table Valued Function, rather than a procedure)
First create a real, permanent table as a template that has the required layout for the returned temporary table, using a naming convention that identifies it as a template and links it symbolically to the SP, eg tmp_SPName_Output. This table will never contain any data.
In the SP, use INSERT to load data into a temp table following the same naming convention, e.g. #SPName_Output which is assumed to exist. You can test for its existence and return an error if it does not.
Before calling the sp use this simple select to create the temp table:
SELECT TOP(0) * INTO #SPName_Output FROM tmp_SPName_Output;
EXEC SPName;
-- Now process records in #SPName_Output;
This has these distinct advantages:
The temp table is local to the current session, unlike ##, so will not clash with concurrent calls to the SP from
different sessions. It is also dropped automatically when out of scope.
The template table is maintained alongside the SP, so if changes are
made to the output (new columns added, for example) then pre-existing
callers of the SP do not break. The caller does not need to be changed.
You can define any number of output tables with different naming for
one SP and fill them all. You can also define alternative outputs
with different naming and have the SP check the existence of the temp
tables to see which need to be filled.
Similarly, if major changes are made but you want to keep backwards
compatibility, you can have a new template table and naming for the later
version but still support the earlier version by checking which temp
table the caller has created.

Resources