Declare dynamic table which will use later in sql server procedures? - sql-server

I am working on sql stored procedure and I got some issue description given below:
Working Process
Declare a table name #summaryTable
DECLARE #summaryTable table (
id int identity(1,1),
)
Then make a query and then insert data into table #summaryTable, code given below:
set #query = "Select * from Foo"
insert into #summaryTable exec(#query)
Problem
When I print table name such as print #summaryTable, simply it give me the
error that
`Msg 137, Level 16, State 1, Procedure summaryReportExport, Line 71
Must declare the scalar variable "#summaryTable".`
Actually I need to use above table-name while creating .csv file such as
Declare #resultSet nvarchar(max)
set #resultSet = "Select foo from '+#summaryTable"
Declare #sql varchar(8000) set #sql = 'xp_cmdshell '
Declare #fileName varchar(8000) set #fileName = 'c:/test.csv'
set #sql = #sql + '''' + ' bcp "' + #resultSet+'"' +' queryout '+ #fileName +' -T -c -t,' + '''' ;
print #sql
EXEC (#sql)
Any help would be appreciated?

Temporary tables come in different flavours including, amongst others, local temporary tables (starting with #), global temporary tables (starting with ##), persistent temporary tables (prefixed by TempDB..), and table variables.(starting with (#)
if we declare with #tableName then it works as a variable it should be the part of query.Table variables are used within the scope of the routine or batch within which they are defined
DECLARE #summaryTable table (
id int identity(1,1),
)
if you declare #tableName it's mean local table only you can use it for this session.With Local temporary table (names that begin with #), what goes on under the hood is surprisingly similar to table variables. As with Table Variables, Local Temporary tables are private to the process that created it. They cannot therefore be used in views and you cannot associate triggers with them
CREATE TABLE #summaryTable (
id int identity(1,1),
)
if you declare ##tableName it's mean global table any one can use for this session.Like Local temporary tables, Global temporary tables (they begin with ##) are automatically dropped when the session that created the table ends: However, because global tables aren’t private to the process that created it, they must persist thereafter until the last Transact-SQL statement that was actively referencing the table at the time when the creating session ended has finished executing and the locks are dropped. Anyone who has access to TempDB at the time these Global Temporary tables exist can directly query, modify or drop these temporary objects.
You can associate rules, defaults, and indexes with temporary tables, but you cannot create views on temporary tables or associate triggers with them. You can use a user-defined datatype when creating a temporary table only if the datatype exists in TempDB
CREATE TABLE ##summaryTable (
id int identity(1,1),
)
this Reference more help you

You can try CREATE TABLE #TableName (id int identity(1,1)) this will create a temp table. And then add DROP TABLE #TableName to the end of you script.
But iam not sure what it is you want with this? You are trying to read a file into somthing ?
For more information on Temp Tables, read: https://www.simple-talk.com/sql/t-sql-programming/temporary-tables-in-sql-server/ and http://www.sqlteam.com/article/temporary-tables .

Related

Create table variable with exact same structure of another table

In T-SQL, I can create a table variable using syntax like
DECLARE #table AS TABLE (id INT, col VARCHAR(20))
For now, if I want to create an exact copy of a real table in the database, I do something like this
SELECT *
FROM INFOMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'MY_TABLE_NAME'
to check the column datatype and also max length, and start to create the #table variable, naming the variable, datatype and max_length one by one which is not very effective. May I know if there is any simpler way to do it like
DECLARE #table AS TABLE = SOME_REAL_TABLE_IN_DATABASE
Furthermore, is there any way to retrieve the column name, data type and max length of the column and use it directly in the declaration like
DECLARE #table AS TABLE (#col1_specs)
Thank you in advance.
EDIT:
Thanks for the answers and comments, we can do that for #table_variable but only in dynamic SQL and it is not good for maintainability. However, we can do that using #temp_table.
Based on the answer by Ezlo, we can do something like this :
SELECT TABLE.* INTO #TEMP_TABLE FROM TABLE
For more information, please refer to this answer.
Difference between temp table and table variable (stackoverflow)
Difference between temp table and table variable (dba.stackexchange)
Object names and data types (tables, columns, etc.) can't be parameterized (can't come from variables). This means you can't do the following (which would be required to copy a table structure, for example):
DECLARE #TableName VARCHAR(50) = 'Employees'
SELECT
T.*
FROM
#TableName AS T
The only workaround is to use dynamic SQL:
DECLARE #TableName VARCHAR(50) = 'Employees'
DECLARE #DynamicSQL VARCHAR(MAX) = '
SELECT
T.*
FROM
' + QUOTENAME(#TableName) + ' AS T '
EXEC (#DynamicSQL)
However, variables (scalar and table variables) declared outside the dynamic SQL won't be accessible inside as they lose scope:
DECLARE #VariableOutside INT = 10
DECLARE #DynamicSQL VARCHAR(MAX) = 'SELECT #VariableOutside AS ValueOfVariable'
EXEC (#DynamicSQL)
Msg 137, Level 15, State 2, Line 1
Must declare the scalar variable "#VariableOutside".
This means that you will have to declare your variable inside the dynamic SQL:
DECLARE #DynamicSQL VARCHAR(MAX) = 'DECLARE #VariableOutside INT = 10
SELECT #VariableOutside AS ValueOfVariable'
EXEC (#DynamicSQL)
Result:
ValueOfVariable
10
Which brings me to my conclusion: if you want to dynamically create a copy of an existing table as a table variable, all the access of your table variable will have to be inside a dynamic SQL script, which is a huge pain and has some cons (harder to maintain and read, more prone to error, etc.).
A common approach is to work with temporary tables instead. Doing a SELECT * INTO to create them will inherit the table's data types. You can add an always false WHERE condition (like WHERE 1 = 0) if you don't want the actual rows to be inserted.
IF OBJECT_ID('tempdb..#Copy') IS NOT NULL
DROP TABLE #Copy
SELECT
T.*
INTO
#Copy
FROM
YourTable AS T
WHERE
1 = 0
The answer for both questions is simple NO.
Although, I agree with you that T-SQL should change in this way.
In the first case, it means having a command to clone a table structure.
Of course, there is a possibility to make your own T-SQL extension by using SQLCLR.

Use variable to create new table in ms sql

create proc City_Info
#StateRef nvarchar(20)
as
begin
declare #StateCod nvarchar(3);
declare #Check int;
select #StateCod = StateCod from State_Cod where State_Nam = #StateRef
create table C0NCAT(#StateCod' ,'City')(Sno int identity(1,1))
end
Can Anyone tell how can i fetch a Particular Name from Column and Make table using Procedure in mssql?
First of all it looks like classic example of SELECT * FROM sales + #yymm
This is a variation of the previous case, where there is a suite of tables that actually do describe the same entity. All tables have the same columns, and the name includes some partitioning component, typically year and sometimes also month. New tables are created as a new year/month begins.
In this case, writing one stored procedure per table is not really feasible. Not the least, because the user may want to specify a date range for a search, so even with one procedure per table you would still need a dynamic dispatcher.
If you still want to go this way you could use Dynamic-SQL.
create proc City_Info
#StateRef nvarchar(20)
as
begin
declare #StateCod nvarchar(3);
declare #Check int;
select #StateCod = StateCod from State_Cod where State_Nam = #StateRef;
DECLARE #sql NVARCHAR(MAX) =
'create table '
+ QUOTENAME(C0NCAT(#StateCod ,'City'))
+ '(Sno int identity(1,1))';
EXEC sp_executesql #sql
end

Use trigger to modify column data type length

My program will create a temp table which will drop after the program executed. The data type length is 8. But I want to change the length to 15 when I run the program using the trigger function in Sql Server. I have few table that need to change the length. Is there any way to change the length without stating the table name in trigger function?
Clarification:
I have 100 programs which will create temporary table with different names. Each temp table will have user_id varchar(8). So i want to change the length to 15 . But i dont want to open my each program's source code to change it. is there a better way that you can suggest me?
What you want is essentially possible to achive using DDL triggers.
CREATE TRIGGER [TRG_TABLES]
ON DATABASE
AFTER
CREATE_TABLE
AS
BEGIN
SET NOCOUNT ON
DECLARE #TABLE_NAME SYSNAME
SELECT
#TABLE_NAME = EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]','SYSNAME')
IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TABLE_NAME
AND COLUMN_NAME = 'TEST')
BEGIN
DECLARE #SQL as NVARCHAR(MAX) ='ALTER TABLE ' + #TABLE_NAME + ' ALTER COLUMN TEST NVARCHAR(200) '
Exec sp_ExecuteSql #SQL
END
END
GO
ENABLE TRIGGER [TRG_TABLES] ON DATABASE
You should be EXTRA careful about SQL injection if you use this approach.
EDIT: This is just a general idea you should probably figure out under which conditions you should alter the column - if there is a predictable pattern to your table names.

SQL Server : update records in dynamically generated tables using parameters in stored procedure

I have to create a stored procedure where I will pass tableName, columnName, id as parameters. The task is to select records from the passed table where columnName has passed id. If record is found update records with some fixed data. Also implement Transaction so that we can rollback in case of any error.
There are hundreds of table in database and each table has different schema that is why I have to pass columnName.
Don't know what is the best approach for this. I am trying select records into a temp table so that I can manipulate it as per requirement but its not working.
I am using this code:
ALTER PROCEDURE [dbo].[GetRecordsFromTable]
#tblName nvarchar(128),
#keyCol varchar(100),
#key int = 0
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
--DROP TABLE #TempTable;
DECLARE #sqlQuery nvarchar(4000);
SET #sqlQuery = 'SELECT * FROM ' + #tblName + ' WHERE ' + #keyCol + ' = 2';
PRINT #sqlQuery;
INSERT INTO #TempTable
EXEC sp_executesql #sqlQuery,
N'#keyCol varchar(100), #key int', #keyCol, #key;
SELECT * FROM #TempTable;
END TRY
BEGIN CATCH
EXECUTE [dbo].[uspPrintError];
END CATCH;
END
I get an error
Invalid object name '#TempTable'
Also not sure if this is the best approach to get data and then update it.
If you absolutely must make that work then I think you'll have to use a global temp table. You'll need to see if it exists before running your dynamic sql and clean up. With a fixed table name you'll run into problems with other connections. Inside the dynamic sql you'll add select * into ##temptable from .... Actually I'm not even sure why you want the temp table in the first place. Can't the dynamic sql just return the results?
On the surface it seems like a solid idea to have one generic procedure for returning data with a couple of parameters to drive it but, without a lot of explanation, it's just not the way database are designed to work.
You should create the temp table.
IF OBJECT_ID('tempdb..##TempTable') IS NOT NULL
DROP TABLE ##TempTable
CREATE TABLE ##TempTable()

Dynamically named temp table returns "invalid object name" when referenced in stored procedure

When I run the following code, I get an "invalid object name" error, any idea why?
I need to create a dynamically named temp table to be used in a stored procedure.
DECLARE #SQL NVARCHAR(MAX)
DECLARE #SessionID NVARCHAR(50)
SET #SessionID = 'tmp5l7g9q3l1h1n5s4k9k7e'
;
SET
#SQL = N' CREATE TABLE #' + #SessionID + ' ' +
N' (' +
N' CustomerNo NVARCHAR(5), ' +
N' Product NVARCHAR(3), ' +
N' Gross DECIMAL(18,8) ' +
N' )'
;
EXECUTE sp_executesql #SQL
;
SET
#SQL = N' SELECT * FROM #' + #SessionID
;
EXECUTE sp_executesql #SQL
Thanks!
WHY MESS WITH THE NAMES? Let SQL Server will manage this for you:
Temporary Tables in SQL Server
from the above link:
If the same routine is executed simultaneously by several processes,
the Database Engine needs to be able to distinguish between the
identically-named local temporary tables created by the different
processes. It does this by adding a numeric string to each local
temporary table name left-padded by underscore characters. Although
you specify the short name such as #MyTempTable, what is actually
stored in TempDB is made up of the table name specified in the CREATE
TABLE statement and the suffix. Because of this suffix, local
temporary table names must be 116 characters or less.
If you’re interested in seeing what is going on, you can view the
tables in TempDB just the same way you would any other table. You can
even use sp_help work on temporary tables only if you invoke them from
TempDB.
USE TempDB
go
execute sp_Help #mytemp
or you can find them in the system views of TempDB without swithching
databases.
SELECT name, create_date FROM TempDB.sys.tables WHERE name LIKE '#%'
You are doing it wrong!
Try:
exec(#SQL)
instead of:
EXECUTE sp_executesql #SQL
To use sp_executesql the variable must be inside #SessionID the quotes and it must be provided has input parameter. Check this for a full example!
You've to be aware that Dynamic SQL is a good port for SQL injections!
This syntax works
CREATE TABLE #SessionID (CustomerNo NVARCHAR(5), Product NVARCHAR(3), Gross DECIMAL(18,8));
Select COUNT(*) from #SessionID;
Drop Table #SessionID;

Resources