Drop/Create Table (SQL - Procedure) - sql

I'm trying to create a very simple procedure (with a simple code - I'm a beginner and I want to keep my code as simple as possible) which can Drop a table named "Table1" and Create a table named "Students" containing 3 columns: ID, Name, Mark
This is my code and it doesn't work at all:
CREATE PROCEDURE Drop_Create
#Table1 VARCHAR(MAX),
#Students VARCHAR(MAX)
AS
BEGIN
DECLARE #SQL VARCHAR(MAX);
SELECT #SQL = 'CREATE TABLE ' + #Students + '('SELECT #SQL = #SQL + '[ID] [int] IDENTITY(1,1) NOT NULL,[Name] [NVARCHAR(50)] NOT NULL,[Mark] [INT])';
SET #SQL = 'IF EXISTS DROP TABLE [' + #Table1 + ']'
PRINT #SQL;
EXEC #SQL;
END
GO

Are you intentionally using dynamic SQL? If the table names are static, ditch that approach. Otherwise:
Issue 1, Your if exists.. was totally wrong.
Issue 2, You overwrote #SQL without executing the first task
Issue 3, You had square brackets around [Varchar(50)]
Even as you have it now, it will break the second time you run it (it will try to create #Students again). I suspect you're confusing yourself with the logic somehow.
CREATE PROCEDURE Drop_Create
#Table1 VARCHAR(MAX),
#Students VARCHAR(MAX)
AS
BEGIN
-- Drop #table1
DECLARE #SQL VARCHAR(MAX) = 'IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N''' + #Table1 + ''') AND type in (N''U'')) DROP TABLE [' + #Table1 + ']'
PRINT #SQL;
EXEC (#SQL);
-- Create #Students
SET #SQL = 'CREATE TABLE ' + #Students + '('
SET #SQL = #SQL + '[ID] [int] IDENTITY(1,1) NOT NULL,[Name] NVARCHAR(50) NOT NULL,[Mark] [INT])';
PRINT #SQL;
EXEC (#SQL);
END
GO

Related

Passing in table name and row info into an INSERT INTO stored procedure

I want to pass into the procedure the table name and the values without mentioning column names because I want to be able to use this on any table.
#row would be csv string like 'test','123'
My code causes an error:
CREATE PROCEDURE test
#table NVARCHAR(100),
#row NVARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Sql NVARCHAR(MAX)
SET #sql = 'INSERT INTO ' + #table+ 'VALUES (' + #row + ')'
EXEC sp_executesql #sql
END
Please try this.
SQL
CREATE PROCEDURE test
#table NVARCHAR(100),
#row NVARCHAR(max)
AS
BEGIN
DECLARE #Sql NVARCHAR(MAX)
SET #sql = 'INSERT INTO [dbo].[' + #table+ '] VALUES (' + #row + ')'
EXEC sp_executesql #sql
END
Note: if you select table name dynamic and you are pass single values it means the table has single columns
If you pass any other table and table has multiple columns your insert statement not work.

TSQL: Using 'Output' clause in dynamic SQL

I'm using an Output clause in my Insert statement which requires use of a Table Variable. I also want the Table name to be dynamic so I'm using dynamic SQL but it won't allow use of a Table Variable. I get the error Must declare the scalar variable "#InsertedId".
CREATE PROCEDURE sp_InsertPerson #Name varchar(50), #Table varchar(20) AS
DECLARE #InsertedId TABLE (Id int)
DECLARE #SQL nvarchar(200) = 'INSERT INTO ' + #Table + ' (Name) OUTPUT INSERTED.Id INTO ' + #InsertedId + ' VALUES (' + #Name + ')'
IF (#Name is not null AND #Name != '')
EXEC(#SQL)
SELECT Id FROM #InsertedId
How can I both use the Output clause and a dynamic Table name
First of all, do not use sp_ prefix to your stored procedure, cause it reserved to System stored procedures by MS, and can lead to performance issue and other problems (as it can be a habit). Use SysName datatype for the table name, and use QUOTENAME() function when you concatenate the string.
You need to declare your table in the DynamicSQL as
CREATE PROCEDURE InsertPerson
#Name varchar(50),
#Table SysName
AS
DECLARE #SQL NVARCHAR(MAX);
SET #SQL = N'DECLARE #IDs TABLE (ID INT);'+
'INSERT INTO ' +
QUOTENAME(#Table) +
' (Name) OUTPUT INSERTED.ID INTO #IDs VALUES(#Name);'+
'SELECT * FROM #IDs';
EXECUTE sp_executesql #SQL,
N'#Name VARCHAR(50)',
#Name;
Demo
Try this;
CREATE PROCEDURE sp_InsertPerson #Name varchar(50), #Table varchar(20) AS
DECLARE #SQL nvarchar(200) = ''
SET #SQL = #SQL + 'DECLARE #InsertedId TABLE (Id int)';
SET #SQL = #SQL + 'INSERT INTO ' + #Table + ' (Name) OUTPUT INSERTED.Id INTO #InsertedId (Id) VALUES (''' + #Name + ''')'
SET #SQL = #SQL + 'SELECT Id FROM #InsertedId'
IF (#Name is not null AND #Name != '')
EXEC(#SQL)

How to use Table -Valued Parameter with Dynamic qry

I am using Table - Valued Parameter for to build dyNamic Query Using the Following code
AlTER PROCEDURE [dbo].[ABC]
#tblName Varchar(1000),
#Details ABC_TYPE Readonly
AS
BEGIN
Declare #PK as nvarchar(1000)
Declare #SyncFlag as nvarchar(1) ='S'
Declare #SelectCommand as nvarchar(1200)
Declare #tblName2 as nvarchar(1000) ='#Details_N'
Set #PK = 'PK'
Declare #Details_N as table (Pk int)
Insert into #Details_N(Pk)
select PK from #Details
set #SelectCommand = 'Update A ' + ' set A.Sync_Flag ='''+ #SyncFlag + ''' From '+ #tblName + ' A, ' + #tblName2 + ' B ' +
' where A.' + #PK +'='+ 'B.PK'
EXEC sp_executesql #SelectCommand;
This giving me error
Must declare the table variable "#Details_N"
Not finding where my I am doing wrong
Inside dynamic query, you cannot use table variables declared outside. Use temp table instead. Also you have complicated it little too much, here is a cleaner version
DECLARE #SyncFlag AS NVARCHAR(1) ='S'
DECLARE #SelectCommand AS NVARCHAR(1200)
CREATE TABLE #Details_N(Pk INT)
INSERT INTO #Details_N(Pk)
SELECT PK
FROM #Details
SET #SelectCommand = 'Update A ' + ' set A.Sync_Flag = #SyncFlag
From '+ Quotename(#tblName) + ' A
inner join #Details_N B '+ 'on A.PK =' + 'B.PK'
EXEC Sp_executesql
#SelectCommand,
N'#SyncFlag NVARCHAR(1)',
#SyncFlag
Start using INNER JOIN syntax, old style comma separated join is deprecated
The scope of Table Variable is for specific batch (same context) while Temporary table is for SPID. The EXEC command runs in different context. Use temporary tables instead:
Declare #tblName2 as nvarchar(1000) ='#Details_N'
CREATE TABLE #Details_N (Pk int)
Insert into #Details_N(Pk)
select PK from #Details

T-SQL Create Table with Dynamically Named Database with sp_executesql

I am attempting to create a table in T-SQL using sp_executesql. The name of the database containing the table is dynamic.
DECLARE #ID int = 1031460
DECLARE #TableName nvarchar(max) = '[MyDatabase' + CAST(#ID as nvarchar(10)) + '].[dbo].[MyTable]'
DECLARE #CreateTable nvarchar(max) = N''
SELECT #CreateTable =
N'
CREATE TABLE #TableName
(
ID int
)
'
EXECUTE sp_executeSQL #CreateTable, N'#TableName nvarchar(max)', #TableName = #TableName
This script results in this error:
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near '#TableName'.
What is the best way to specify the name of the table to create dynamically based on parameters of sp_executeSQL?
You cannot pass Tablename as a parameter even we using sp_executesql procedure. You have to build you own dynamic sql query
SELECT #CreateTable =
N'
CREATE TABLE ' + #TableName + '
(
ID int
)
'
Exec sp_executesql #CreateTable
When you are passing the table name as a parameter to sp_executesql, it treats it as a literal string, to make it treat it as an object name try something like this......
DECLARE #ID int = 1031460
DECLARE #TableName nvarchar(max) = QUOTENAME('MyDatabase' + CAST(#ID as nvarchar(10)))
+ '.[dbo].[MyTable]'
DECLARE #CreateTable nvarchar(max);
SET #CreateTable = N' CREATE TABLE ' + #TableName
+ N' (
ID int
)'
Exec sp_executesql #CreateTable
EDIT
It is good practice to check if an object already exists before you try to create it.
You can check if the object already exists and drop it and then create the new one, you code should look something like.....
DECLARE #ID int = 1031460
DECLARE #TableName nvarchar(max) = QUOTENAME('MyDatabase' + CAST(#ID as nvarchar(10)))
+ '.[dbo].[MyTable]'
DECLARE #CreateTable nvarchar(max), #DropTable nvarchar(max);
-- Drop table if already exists
SET #DropTable = N' IF OBJECT_ID('''+ #TableName +''') IS NOT NULL '
+ N' DROP TABLE ' + #TableName
Exec sp_executesql #DropTable
SET #CreateTable = N' CREATE TABLE ' + #TableName
+ N' (
ID int
)'
Exec sp_executesql #CreateTable

using temp tables in SQL Azure

I am writing a query to pivoting table elements where column name is generated dynamically.
SET #query = N'SELECT STUDENT_ID, ROLL_NO, TITLE, STUDENT_NAME, EXAM_NAME, '+
#cols +
' INTO ##FINAL
FROM
(
SELECT *
FROM #AVERAGES
UNION
SELECT *
FROM #MARKS
UNION
SELECT *
FROM #GRACEMARKS
UNION
SELECT *
FROM #TOTAL
) p
PIVOT
(
MAX([MARKS])
FOR SUBJECT_ID IN
( '+
#cols +' )
) AS FINAL
ORDER BY STUDENT_ID ASC, DISPLAYORDER ASC, EXAM_NAME ASC;'
EXECUTE(#query)
select * from ##FINAL
This query works properly in my local database, but it doesn't work in SQL Azure since global temp tables are not allowed there.
Now if i change ##FINAL to #FINAL in my local database, but it gives me error as
Invalid object name '#FINAL' .
How can I resolve this issue?
Okay, after saying I didn't think it could be done, I might have a way. It's ugly though. Hopefully, you can play with the below sample and adapt it to your query (without having your schema and data, it's too tricky for me to attempt to write it):
declare #cols varchar(max)
set #cols = 'object_id,schema_id,parent_object_id'
--Create a temp table with the known columns
create table #Boris (
ID int IDENTITY(1,1) not null
)
--Alter the temp table to add the varying columns. Thankfully, they're all ints.
--for unknown types, varchar(max) may be more appropriate, and will hopefully convert
declare #tempcols varchar(max)
set #tempcols = #cols
while LEN(#tempcols) > 0
begin
declare #col varchar(max)
set #col = CASE WHEN CHARINDEX(',',#tempcols) > 0 THEN SUBSTRING(#tempcols,1,CHARINDEX(',',#tempcols)-1) ELSE #tempcols END
set #tempcols = CASE WHEN LEN(#col) = LEN(#tempcols) THEN '' ELSE SUBSTRING(#tempcols,LEN(#col)+2,10000000) END
declare #sql1 varchar(max)
set #sql1 = 'alter table #Boris add [' + #col + '] int null'
exec (#sql1)
end
declare #sql varchar(max)
set #sql = 'insert into #Boris (' + #cols + ') select ' + #cols + ' from sys.objects'
exec (#sql)
select * from #Boris
drop table #Boris
They key is to create the temp table in the outer scope, and then inner scopes (code running within EXEC statements) have access to the same temp table. The above worked on SQL Server 2008, but I don't have an Azure instance to play with, so not tested there.
If you create a temp table, it's visible from dynamic sql executed in your spid, if you create the table in dynamic sql, it's not visible outside of that.
There is a workaround. You can create a stub table and alter it in your dynamic sql. It requires a bit of string manipulation but I've used this technique to generate dynamic datasets for tsqlunit.
CREATE TABLE #t1
(
DummyCol int
)
EXEC(N'ALTER TABLE #t1 ADD foo INT')
EXEC ('insert into #t1(DummyCol, foo)
VALUES(1,2)')
EXEC ('ALTER TABLE #t1 DROP COLUMN DummyCol')
select *from #t1