Way to get the CREATE statement of global temporary table? - sql-server

I have stored procedures I need to rewrite that used global temporary tables but now must use local temporary tables so that there is no cross over between users/the prod and dev db which are on the same SQL Server instances or any other new databases this database will be share the instance with.
I have to convert a lot of code that is like this
EXEC sp_executesql
N'SELECT manyDynamicallyCreatedColumns INTO ##someTempTable
I now for this to work for local tables I must instead create the table first and then INSERT INTO like
CREATE TABLE #tempTable (manyColumns);
EXEC sp_executesql
N'INSERT INTO #tempTable SELECT manyColumns FROM somewhere'
The issue I face is that this stored procedure has 8 different scenarios that lead to the global temp table. The select statement of the SQL is dynamically generated via a number of other queries. I think what would be the easiest way for me to figure out what my CREATE TABLE #tempTable should look like is if I could print/select what global temporary table looks like after it is made, for each of these 8 scenarios. Then I would just need a If/Else If statement that creates the local table appropriately before proceeding. But I don't know how or if this is possible.
For real tables I can right click -> Script to...-> Create. I don't know if there is an analogous way to do this via scripting that works for global temporary tables. Is there?

Related

Using SQL Server local temporary table with MyBatis

In MS SQL Server, the local temporary table is prefixed with a # in the table name.
select * from #foo
But MyBatis uses # for specifying placeholders.
How can I use SQL Server's local temporary table with MyBatis?
I tried various possible escape methods, but none of them worked.
You can go for one of the following approach for fixing your problem.
1- Go for a stored procedure, in the stored procedure you can do what ever you want.
2- Use #Table instead of #Table (If your data is not huge and you don't need feature like index creation/trunation etc)

Syntax for creating temp table with their unique name by select query in stored procedure using SQL Server

I want to create temp table with their unique name by a select query in a stored procedure in SQL Server.
For example: whenever I run the select query at that time different temp table name want to create.
Let be more clear, at the first time when I will run the select query at that time temptable name is temptable1, while at the second time the table name will be temptable2 and so on.
I want to know the syntax for executing the select query and creating the temptable with their unique name in a stored procedure in SQL Server.
In the context of the SQL Server Stored Procedure, the engine is handling itself the names of the temporary tables.
There is no need to worry if many users are executing the same stored procedure in same time - the temporary objects cannot be shared across them and no conflicts are going to happen.
Also, naming a temporary table in stored procedure with different name can be done using a dynamic T-SQL statement. You can for example, use a sequence to get such number and concatenate it to the table name. But, if you do so, you need to use sp_executesql to create your table and do things with it. In such way, no other stored procedure would be able to read/modify the table you have created in the current stored procedure. In other words, the temporary table cannot be shared over the routines if created using dynamic T-SQL statement. So, there is absolutely no point of doing such thing.

How to create a table that exist temporarily and that is accessible from many stored procedures?

I query my database from within a .NET application (time recoding). I send the Windows user name to the database and query it depending on this information.
I query a lot of different information with stored procedures, such as holiday, overtime etc. and send them back to the .NET application where I show this data in one form.
Let's say I need the information from SP1, 3 and 4 on Form1:
FORM1:
SP1
SP3
SP4
My problem:
I have a quite complicated table that I need for these stored procedures. At the moment I create this table in every of those stored procedures as temporary tables what is obviously quite time consuming.
What I have tried so far is creating a stored procedure that creates a temp table but this one is not accessable within my other stored procedures.
My question: I am looking for a way to create this table for Form1 once, so I can just access these table in the other stored procedures.
I'm using SQL Server 2014 Express.
If you create the temporary table outside of any stored procedure, it will be accessible within each. Assuming that the actual table definition isn't too complex (but populating it may be), this may be doable.
So you'd execute (effectively):
CREATE TABLE #T (A int not null, B varchar(17) not null)
EXEC PopulateTempTable
EXEC SP1
EXEC SP3
EXEC SP4
All on a single connection. PopulateTempTable may or may not be required, depending on how complex the population of the table is and whether you want that to be performed by your calling code or the database.
You cannot create the temp table inside of a stored procedure since temp tables are automatically dropped when the scope of a stored procedure is exited.
Alternatively, you may want to simulate "session-global" temp tables, as I suggest in this answer1.
The risk with using a global temp table is that it is truly global - all sessions see and interact with the data in the same table. You have to be very careful in such circumstances if it's at all possible that two sessions will attempt to use it at the same time; You generally need some means to filter the data in the table so that each session only works with its own data.
1Probably enhanced these days by also adding a Logon Trigger to clear down the old contents of the table whenever a new connection is established.
You have to create global temp table
CREATE TABLE ##TEMP1
(
Name varchar(50)
)

Change table variable to temp table

I have a certain stored procedure written years ago. It uses a table variable. Inside the code it's doing:
declare #OpportunityVS3 as SF_OpportunityMerge
insert #TableVariable select * from /*...*/
This is inside a job that runs every five minutes. There used to be no issues in the past because the select used to collect around 10 to 1000 records… But now sometimes the select is trying to insert a million records.
Given this issue, I think I am forced to change the #TableVariable to a #TempTable. What do you think? Do I have any other option?
At the end of the SP, it’s passing the Variable to another SP:
exec [dbo].[SF_MergeOpportunity] #OpportunityVS3, #LastUpdateDate
I guess I will have to write it all in the same stored procedure, because temporary tables cannot be passed, right?
Below is the definition of the #TableVariable that is being used and the code I would have to change:
declare #OpportunityVS3 as SF_OpportunityMerge
insert #OpportunityVS3 select Opportunity_id, Salesforce_id, AccountId, Age__c,
-- (continues)
merge [BU2].[dbo].[Salesforce_Opportunity] as TARGET
using ( select Opportunity_id,
Salesforce_id,
AccountId,
Age__c,
Amount,
Bill99Amount__c,
BJ_Marketing__c
-- (continues)
from #OpportunityVS3 ) as SOURCE on (TARGET.Opportunity_id = SOURCE.Opportunity_id)
exec [dbo].[SF_MergeOpportunity] #OpportunityVS3, #LastUpdateDate
[![enter image description here][1]][1]
[![enter image description here][2]][2]
What you can try without changing the way you work:
Force the compiler to take cardinalities of TABLE variables into account by specifying OPTION(RECOMPILE) in queries using the TABLE variables
Supply a suitable UNIQUE INDEX or PRIMARY KEY for the TABLE variable
A downside of TABLE variables is that there are no statistics associated with them. The SQL compiler will produce better execution plans when it can take statistics into account. Therefore you can improve performance considerably when you switch to temporary tables because these do have statistics.
When you switch to temporary tables, you would no longer pass a TABLE variable to your stored procedure anymore. Your stored procedure would then be written using a temporary table that it knows exists beforehand - ie was created before the stored procedure is executed.
You would write your stored procedure as though the temporary table were an ordinary table. When you write the stored procedure using a temporary table, SQL Server management studio will underline certain parts in red so it appears as though there are errors in your stored procedure. But if the syntax is correct, creating/altering the stored procedure will work just fine.
Read this excellent essay on the differences between TABLE variables and temporary tables, to see how usage may impact performance. Especially topics No column statistics and Indexes.

Why temporary table is not allowed in stored procedure in Firebird?

I am trying to create temporary table in stored procedure in Firebird database.
My stored procedure listing:
SET TERM ^ ;
CREATE PROCEDURE initNATIONALHEALTHFUNDS
AS BEGIN
CREATE GLOBAL TEMPORARY TABLE temp_FUNDS
(
NATIONALHEALTHFUNDID Integer NOT NULL,
NAME Varchar(128) NOT NULL,
CODE Integer NOT NULL
)
ON COMMIT PRESERVE ROWS;
commit;
INSERT INTO tempFUNDS (NATIONALHEALTHFUNDID, CODE, NAME) VALUES ( 01 ,01 , 'Some Foundation');
MERGE INTO NATIONALHEALTHFUNDS AS target
USING tempFUNDS AS source
ON target.NATIONALHEALTHFUNDID = source.NATIONALHEALTHFUNDID
WHEN NOT MATCHED THEN
INSERT (NATIONALHEALTHFUNDID, CODE, NAME) VALUES (source.NATIONALHEALTHFUNDID, source.CODE, source.NAME);
drop TABLE tempFUNDS;
END^
SET TERM ; ^
Each time I am trying create this procedure I am getting error:
Engine Code : 335544569
Engine Message :
Dynamic SQL Error
SQL error code = -104
Token unknown - line 7, column 3
CREATE
Total execution time: 0.015s
What I am doing wrong? I'm using Firebird 3.0 RC
Firebird doesn't allow you to use DDL inside stored procedures, so CREATE statements are disallowed in PSQL. As indicated in the answer by lad2025 you can work around this limitation by using EXECUTE STATEMENT.
However, the idea behind a global temporary table is that you create it once, and they continue to exist so they can be used later. The data is only visible to the connection that created the data, and the data is deleted after transaction commit (ON COMMIT DELETE ROWS) or connection close (ON COMMIT PRESERVE ROWS) depending on the type of global temporary table.
From the Firebird 3.0 Language Reference:
Global temporary tables have persistent metadata, but their contents
are transaction-bound (the default) or connection-bound. Every
transaction or connection has its own private instance of a GTT,
isolated from all the others. Instances are only created if and when
the GTT is referenced. They are destroyed when the transaction ends or
on disconnection.
So instead of trying to create the global temporary table inside your stored procedure, create it first, then create your stored procedure that uses the already defined GTT.
From GTT documentation:
CREATE GLOBAL TEMPORARY TABLE
is a regular DDL statement that is processed by the engine the same way as a CREATE TABLE statement is processed. Accordingly, it not
possible to create or drop a GTT within a stored procedure or trigger.
You can use Dynamic-SQL and wrap your code with EXECUTE STATEMENT as workaround:
SET TERM ^ ;
CREATE PROCEDURE initNATIONALHEALTHFUNDS
AS BEGIN
EXECUTE STATEMENT
'CREATE GLOBAL TEMPORARY TABLE temp_FUNDS
(
NATIONALHEALTHFUNDID Integer NOT NULL,
NAME Varchar(128) NOT NULL,
CODE Integer NOT NULL
)
ON COMMIT PRESERVE ROWS;
commit;';
...
END^
Just to elaborate on the other above correct answers, I use temporary tables mostly for performance issues, like when I have a parameterized subset of data that needs to be query against a larger set like:
select * from MAIN_TABLE
where MAIN_TABLE.ID in (select ID from GTT$IDS)
where GTT$IDS is populated with the subset of ID's.
Sometimes, for highly complex procedures, I have to use multiple temp tables, so I create them in the metadata (outside of PSQL statements, of course) like so:
create global temporary table GTT$IDS_1 (INT1 integer, INT2 integer);
create index IDX_GTT$IDS_11 on GTT$IDS_1 (INT1);
create index IDX_GTT$IDS_12 on GTT$IDS_1 (INT2);
create global temporary table GTT$IDS_2
...
create global temporary table GTT$IDS_3
...
Doing this may be simplistic for some advanced SQL'ers out there, but it makes the most sense to me (carry over technique from my dBase/VFP days) and it's super fast compared to a bunch of complex joins.
I never really took the time to learn how to use the 'PLAN' clause (or get it working right), so basically I use this technique to generate the PLAN through code when I get slow queries, if that makes sense.

Resources