How to make 2 queries execute as one - sql-server

I have 2 queries that i want to execute as one
ALTER TABLE X ADD Y INT
UPDATE X SET Y = Z
When i select them both to execute shows
Invalid column name Y

This is a compiler error. Both the statements are valid, however, the entire batch is compiled first, prior to any execution. As a result, the entire batch fails as before the statements are executed the column Y does not exist in the table X. Though the compiler is "clever" enough to defer the validation for some objects (for example you can CREATE and then INSERT into a TABLE in the same batch) this is not true for things like when you ALTER a TABLE to add a COLUMN.
The "simple" solution would be to put the 2 statements into 2 batches. In an IDE-like application such as SSMS or ADS, you can use GO to separate your statements:
ALTER TABLE X ADD Y INT NULL;
GO
UPDATE X SET Y = Z;
If they must be in the same batch, you can defer the compilation of the second statement. One method would be to execute the statement with sys.sp_executesql. This would mean that the statement executed by the procedure would not be compiled until sys.sp_executesql itself is executed; which is after the table was ALTERed:
ALTER TABLE X ADD Y INT NULL;
EXEC sys.sp_executesql N'UPDATE X SET Y = Z;';

Related

Extract all SQL commands called in SQL Server stored procedure

Let's say there is a stored procedure:
------
/****** This is my procedure
Dev
author
build date
last modified date
**********/
-- procedure starts
create procedure [temp_my_proc]
begin
declare var1, var2, .. var N
-- 1st select
select a, b, c, d
from mytable_1;
-- delete record
delete from mytable_2;
-- insert record select
insert into mytable_4
select x, y, z
from mytable_3;
end
Now I want to extract the SQL used in this stored procedure by using some SQL command. I tried using these commands:
create table #tmp
(
id int identity(1, 1),
sqlsyntax varchar(max)
);
insert into #tmp (sqlsyntax)
exec sp_helptext temp_my_proc;
select *
from #tmp;
But select * from #tmp is spitting out entire definition of the stored procedure in separate rows. How I can extract just the 3 SQL statements from the stored procedure by omitting all multiple line or single line comment present in the stored procedure?
Expected results is
select a, b, c, d
from mytable_1;
delete from mytable_2;
insert into mytable_4
select x, y, z
from mytable_3;
For modern versions of SQL Server STRING_SPLIT() is the one you need. You need to cross apply your text output against string split, splitting on the enter character i.e.
SELECT #tmp.id, lines.value
FROM #tmp
CROSS APPLY STRING_SPLIT(#tql.sqlsyntax,'
') AS lines
That will split your results into one row per line. Unfortunately you would not be able to distinguish multi-line statements from single ones.
Then you can filter by out the comments by checking
WHERE lines.value NOT LIKE '%--%' AND lines.value<> ''
However, some of your comments are enclosed by /* signs, which go across lines. Unfortunately, there is nothing you can do directly. But if you manually replaced the contents of those comments with -- or used a regex to do so you would be able to handle it.

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

Can you add to an SSIS object variable, appending?

We have an SSIS package that calls a Stored Proc to populate a variable object (full result set).
This is fine.
Now we have a need to call that same stored proc again but with different parameters. So really two sets of data that we want stored all together in the same variable object.
If I populate it a second time, does it overwrite what was there, or append to it?
I do this
Execute SQL Task
ResultSet = Full result set
SQLStatement - executes the stored procedure etc.
Result Set
Result Name = 0
Variable Name = User::Subscriptions
I want that to stay. But want to have a second Execute SQL Task that does the exact same thing, just executes the same stored proc with a different parameter. And I want the User::Subscription variable to hold the results of the 1st Execute SQL Task plus the 2nd Execute SQL task. Is this possible?
Adding another Execute SQL Task will overwrite first result set, you can achieve this using the following workaround:
In the Execute SQL task create a Temp table, Insert all result sets into it, select all recored from this temp table in your result set:
Your query will look like:
CREATE TABLE #TblTemp(Column1 varchar(50), .....)
INSERT INTO #TblTemp(Column1 varchar(50), .....)
EXEC Stored_Procedure_1
INSERT INTO #TblTemp(Column1 varchar(50), .....)
EXEC Stored_Procedure_2
SELECT * FROM #TblTemp

Replace redundant Code with SP / UDF

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;

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