SQL Server, Error 102, when using CURSOR, creating a dynamic table - tsql

I got the following error when using CURSOR in creating temp tables:
(1 row(s) affected)
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '?'.
Msg 208, Level 16, State 0, Line 33
Invalid object name '##TEMP_Branch'.
without CURSOR everything works fine.
Here is the entire code:
declare #TableSchema table
(
Id Int Identity(1,1),
Name nVarchar(50),
DataType nVarchar(50)
)
declare #reportid uniqueidentifier
set #reportid = '597d37c0-563b-42f0-99be-a15000dc7a65'
declare #ttl nvarchar(100)
declare cur CURSOR LOCAL for
SELECT title
FROM ReportItems
where reportid = #reportid
and del = 0
ORder by so
open cur
fetch next from cur into #ttl
while ##FETCH_STATUS = 0 BEGIN
INsert #TableSchema Values(#ttl,'nVarchar(max) NULL')
fetch next from cur into #ttl
end
close cur
deallocate cur
Declare #Statement Varchar(1000)
Select #Statement = 'Create Table [##TEMP_Branch](FieldID Varchar(50)'
Select #Statement = COALESCE(#Statement +',','') + Name + ' ' + DataType from #TableSchema
Select #Statement = #Statement + ')'
EXEC(#Statement)
Select * from ##TEMP_Branch
drop table ##TEMP_Branch
Any kind help would be HIGHLY appreciated.

use a table varible
Declare #TEMP_Branch TABLE
(
FieldID varchar(50)
)
it work as regular table, without relation, and dont have to drop, for lager data process, make a permanent table to temporary store the data and after deleto or truncate it

You probably have a title in the ReportItems table that has a blank space or other bad character (question mark) in it.
The first error looks like it coming out of the EXEC(#Statement) because the table definition is invalid.
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '?'.
The second error is probably Select * from ##TEMP_Branch being executed against a temp table that doesn't exist:
Msg 208, Level 16, State 0, Line 33
Invalid object name '##TEMP_Branch'.

Related

Parameterize Bulk Insert for Microsoft SQL Server 2014

I am trying to parameterize the LASTROW argument of a BULK INSERT query.
The last row of data in the textfile I am importing in to SQL Server contains information about the number of rows in the textfile. And I plan to use that number to populate the value of the LASTROW argument of the BULK INSERT query.
An example of the textfile:
20161003|3504|1360|
20161003|3540|1441|
EOF|2
The query I am working on:
DECLARE #FilePath VARCHAR(500)
SELECT #FilePath = 'C:\path\textfile.txt'
DECLARE #file VARCHAR(MAX)
SELECT #file = (SELECT * FROM OPENROWSET(BULK N'C:\path\textfile.txt', SINGLE_CLOB) AS Content)
DECLARE #LastRow INT
DECLARE #LastRow_String VARCHAR(10)
SELECT #LastRow_String = (SELECT SUBSTRING(#file, CHARINDEX('EOF|', #file)+4, LEN(#file)))
SELECT #LastRow = (SELECT CAST(#LastRow_String AS INT))
DECLARE #Query VARCHAR(MAX)
SELECT #Query = ('BULK INSERT [Database].[dbo].[Table] FROM ''' + #FilePath +
''' WITH ( FIELDTERMINATOR = ''|'', ROWTERMINATOR = ''|\n'', LASTROW = ' + #LastRow + ')')
When I execute the above query I get this error message:
Msg 245, Level 16, State 1, Line 11
Conversion failed when converting the varchar value 'BULK INSERT [Database].[dbo].[Table] FROM 'C:\path\textfile.txt' WITH ( FIELDTERMINATOR = '|', ROWTERMINATOR = '|\n', LASTROW = ' to data type int.
Any help is appreciated!
The problem is that LastRow is an integer; you may need to use LastRow_String for the concatenation into Query; if you are concerned about the white spaces, you can do ltrim(rtrim(#LastRow_String))

two table input parameters in stored procedure

I am working on C# project which needs a stored procedure which will take two table names as inputs.
First table will copy data to a temp table which has two columns URL & channelID. This URL column is then matched with other input table's URL column & if match is found then it will update channel id from temp table to other tables channel ID.
I have written stored procedure as
CREATE PROCEDURE [dbo].[UpdateTables]
#excelTable NVARCHAR(128) ,
#TableName NVARCHAR(128)
AS
Declare #channel_Id nvarchar(50)
Declare #url varchar(400)
BEGIN
Select *
Into #Temp
From QUOTENAME(#excelTable)
END
While EXISTS(SELECT * From #Temp ) > 0
Begin
Select Top 1
#channel_Id = channel_Id, #url = url
From #Temp
update QUOTENAME(#TableName)
set channelid = #channelid
where pagefullurl like '%'+ #url + '%'
Delete #Temp
Where channelid = #channelid
End
I don't have much knowledge in TSQL and my above code has errors.
Incorrect syntax near '>'.
Msg 137, Level 15, State 2, Procedure UpdateTables, Line 20
Must declare the scalar variable "#channelid".
Msg 137, Level 15, State 2, Procedure UpdateTables, Line 22
Must declare the scalar variable "#channelid".
Please suggest what changes needs to done
I don't have MS SQL server handy to test it, but you declare your variable as #channel_Id, and later try to use it as #channelid (without the underscore) so you get errors about the undeclared variable.
I've corrected your SP and this is how it should look
CREATE PROCEDURE [dbo].[UpdateTables]
#excelTable NVARCHAR(128) ,
#TableName NVARCHAR(128)
AS
Declare #channel_Id nvarchar(50)
Declare #url varchar(400)
BEGIN
Select *
Into #Temp
From QUOTENAME(#excelTable)
While EXISTS(SELECT * From #Temp )
Begin
Select Top 1
#channel_Id = channel_Id, #url = url
From #Temp
update QUOTENAME(#TableName)
set channelid = #channel_Id
where pagefullurl like '%'+ #url + '%'
Delete #Temp
Where channelid = #channel_Id
End
END

how to use select case statement with sql transaction

i have one crm application. i found query in my db implementation while staff user post reply of inquiry i have to insert new inquiry ans to one table and modify another table data same time. i applied logic of as well as i represent my stored proc. but error occured in this proc.
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[InquiryPostReply]
(
#Inquiry_id VARCHAR(50),
#Priority_type VARCHAR(25),
#Status_name VARCHAR(50),
#Inquiry_Content VARCHAR(1024),
#NewId VARCHAR(50) OUT
)
AS
BEGIN
SET NOCOUNT ON;
declare #var1 int
declare #var2 int
declare #uniqueRef char(14)
set #uniqueRef = dbo.UniqueRefNum(rand(), rand(), rand(), rand())
set #var1= (SELECT [Id] FROM [OmStocks].[dbo].[tbl_Status_master] WHERE (Status_name=#Status_name))
set #var2= (SELECT [Id] FROM [OmStocks].[dbo].[tbl_Priority_master] WHERE (Priority_name=#Priority_type))
SELECT
CASE #Status_name
WHEN 'Open' THEN
BEGIN TRAN;
BEGIN TRY
INSERT INTO [OmStocks].[dbo].[tbl_Inquiry_master]
([Id],[Inquiry_id],[Priority_id],[Status_id],[Inquiry_Content],[TimeStamp])
VALUES
(#uniqueRef,#Inquiry_id,#var2,#var1,#Inquiry_Content,CONVERT(DATETIME,GETDATE(), 101))
UPDATE [OmStocks].[dbo].[tbl_Inquiry_History]
SET [Priority_id] = #var2,[Status_id] = #var1,[IsDisplay] = 1,[IsReplied] = 1,[TimeStamp] = CONVERT(DATETIME,GETDATE(), 101)
WHERE (Inquiry_id=#Inquiry_id)
COMMIT TRAN;
END TRY;
WHEN 'Close' THEN
BEGIN TRAN;
BEGIN TRY
INSERT INTO [OmStocks].[dbo].[tbl_Inquiry_master]
([Id],[Inquiry_id],[Priority_id],[Status_id],[Inquiry_Content],[TimeStamp])
VALUES
(#uniqueRef,#Inquiry_id,#var2,#var1,#Inquiry_Content,CONVERT(DATETIME,GETDATE(), 101))
UPDATE [OmStocks].[dbo].[tbl_Inquiry_History]
SET [Priority_id] = #var2,[Status_id] = #var1,[IsDisplay] = 0,[IsReplied] = 1,[TimeStamp] = CONVERT(DATETIME,GETDATE(), 101),[Activity_expire_time] = CONVERT(DATETIME,GETDATE(), 101)
WHERE (Inquiry_id=#Inquiry_id)
COMMIT TRAN;
END TRY;
END
SET #NewId = #uniqueRef
END
error occured like:
Msg 156, Level 15, State 1, Procedure InquiryPostReply, Line 21
Incorrect syntax near the keyword 'BEGIN'.
Msg 102, Level 15, State 1, Procedure InquiryPostReply, Line 31
Incorrect syntax near ';'.
Msg 102, Level 15, State 1, Procedure InquiryPostReply, Line 43
Incorrect syntax near ';'.
Msg 102, Level 15, State 1, Procedure InquiryPostReply, Line 46
Incorrect syntax near 'END'.
please help me...
You can't use CASE for this. CASE is an expression that returns a single result, not a statement that can be used for control-of-flow. I do understand that CASE is used that way in some other languages, but it's just not possible in T-SQL.
IF #Status_name = 'Open' THEN
BEGIN
-- do stuff
END
IF #Status_name = 'Close' THEN
BEGIN
-- do other stuff
END

Need help in creating a stored procedure to iterate tables in a database, then run a SQL statement on each table

Our application does not delete data as we retain it for a period of time, instead we have a column "deleted" (bit) in most tables of the database that store data which we mark 1 when deleted, otherwise the default is 0.
I'd like to create a stored procedure that iterates all tables in the database, checks for the existence of a column named "deleted" and if it exists, I run a check against the LastUpdatedUtc column (datetime2) and if the date is over 6 months old and deleted = 1 then we delete the row.
This application is under continuous development so tables could be added which is why I want to create a script that iterates tables instead of having to add a line for each table and remember to add them as new tables are added.
Any help in a SQL Server 2008 R2 stored procedure to this would be a great help.
Thank you.
EDIT (thank you Omaer) here is what I've come up with so far. Anyone that knows a better way let me know.
IF OBJECT_ID('tempdb..#tmpTables') IS NOT NULL DROP TABLE #tmpTables
GO
CREATE TABLE #tmpTables
(
ID INT,
TableName NVARCHAR(100) NOT NULL
)
GO
SET NOCOUNT ON
GO
INSERT #tmpTables
SELECT [object_id], [name] FROM sys.all_objects WHERE type_desc = 'USER_TABLE' ORDER BY [name]
DECLARE #TN NVARCHAR(100)
DECLARE #SQL NVARCHAR(max)
DECLARE #PurgeDate VARCHAR(50)
SET #PurgeDate = DATEADD(MONTH, -6, GETUTCDATE())
WHILE (SELECT COUNT(*) FROM #tmpTables) > 0
BEGIN
SELECT TOP 1 #TN = TableName FROM #tmpTables
IF EXISTS(SELECT * FROM sys.columns WHERE name = 'deleted' AND OBJECT_ID = OBJECT_ID(#TN))
BEGIN
IF EXISTS(SELECT * FROM sys.columns WHERE name = 'LastUpdatedUtc' AND OBJECT_ID = OBJECT_ID(#TN))
BEGIN
SET #SQL = 'SELECT Count(*) As Counter FROM ' + #TN + ' WHERE [deleted] = 1 AND [LastUpdatedUtc] < ''' + #PurgeDate + '''' -- this will be the delete line when the code is final, just outputting results for now
EXEC(#SQL)
END
END
DELETE #tmpTables WHERE TableName=#TN
END
DROP TABLE #tmpTables
This is my first attempt, not tested it so there might be some typos/syntax errors but this should get you started:
declare #date6MonthsBack varchar(50)
select #date6MonthsBack = dateadd(month, -6, getdate());
declare c cursor for
select 'delete from ' + quotename(name) + ' where [deleted] = 1 and [LastUpdatedUtc] <= ''' + #date6MonthsBack + '''' from sys.tables
where object_id in (select object_id from sys.columns where name = 'deleted')
and object_id in (select object_id from sys.columns where name = 'LastUpdatedUtc')
declare #sql varchar(max)
open c; fetch next from c into #sql
while (##fetch_status = 0) begin
print(#sql)
--exec(#sql) --uncomment this line to do the actual deleting once you have verified the commands.
fetch next from c into #sql; end
close c; deallocate c
You could use undocummented sp_MSforeactable procedure instead of loop or cursor. Something like code below. I created procedure that runs your code and is executed with sp_MSforeachtable. The disadvantage is - the procedure is undocumented and may not be supported in next SQL Server releases
IF OBJECT_ID('dbo.usp_cleanup') IS NULL
EXEC ('CREATE PROCEDURE dbo.usp_cleanup AS SELECT 1')
GO
ALTER PROCEDURE dbo.usp_cleanup
#sTblName VARCHAR(200)
AS
BEGIN
-- your variables
DECLARE #PurgeDate VARCHAR(50)
DECLARE #SQL VARCHAR(MAX)
SET #PurgeDate = DATEADD(MONTH, -6, GETUTCDATE())
-- we can check columns existence in one condition
IF
EXISTS(SELECT * FROM sys.columns WHERE name = 'deleted' AND OBJECT_ID = OBJECT_ID(#sTblName))
AND EXISTS(SELECT * FROM sys.columns WHERE name = 'LastUpdatedUtc' AND OBJECT_ID = OBJECT_ID(#sTblName))
BEGIN
SET #SQL = 'SQL CODE GOES HERE' -- this will be the delete line when the code is final, just outputting results for now
PRINT #SQL
--EXEC(#SQL) -- uncomment for execution
END
ELSE
-- for debugging
BEGIN
PRINT #sTblName + ' has no [delete] and [LastUpdatedUtc] columns'
END
END
EXEC sp_MSforeachtable 'exec usp_cleanup ''?'''
GO

Incorrect Stored Procedure Syntax

I am using the below stored procedure to upload files into a db where each file has a correspondence table but there are times when the table not exist in that case i want to add the file name into a table called NewTables.I can not get the stored proc syntax working can someone help me.I believe the mistake is in the first part where i check if the table exist
ALTER proc [dbo].[UploadCSVFiles]
#FilePath varchar(100) ,
#FileName varchar(100),
#TableName varchar(250)
AS
BEGIN
DECLARE #SqlStmt nvarchar(max)
DECLARE #ErrorCode int
SET #SqlStmt='Truncate table dbo.[' + #TableName +']'
EXEC(#SqlStmt);
set #SqlStmt =N'
IF not EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N''[dbo].['+#TableName +N']'') AND type in (N''U''))
BEGIN
INSERT INTO dbo.NewTables ('+#TableName+N','+#FileName+N') Values('+#TableName+N','+#FileName+N')
END
ELSE
BEGIN
INSERT INTO '+#TableName+N'
select *
from openrowset(''MSDASQL''
,''Driver={Microsoft Access Text Driver (*.txt, *.csv)};
DefaultDir='+#FilePath+N'''
,''select * from "'+#FileName+N'"'')
END
'
EXEC(#SqlStmt);
Thanks
Rao
Thanks fpop and Christine, I have made the suggestions you made but still I get an error
Msg 4701, Level 16, State 1, Line 1
Cannot find the object "Customer" because it does not exist or you do not have permissions.
it seems the If statement does not insert the new table
here is the final version
USE [MyDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER proc [dbo].[UploadFiles_2]
#FilePath varchar(100) ,
#FileName varchar(100),
#TableName varchar(250)
AS
BEGIN
DECLARE #SqlStmt nvarchar(max)
DECLARE #ErrorCode int
SET #SqlStmt='Truncate table dbo.[' + #TableName +']'
EXEC sp_executesql #SqlStmt;
set #SqlStmt =N'
IF ( NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N''[dbo].['+#TableName +N']'') AND type in (N''U''))
BEGIN
INSERT INTO dbo.NewTables (TableName,FileName) Values('''+#TableName+N''','''+#FileName+N''')
END
ELSE
BEGIN
INSERT INTO '+#TableName+N'
select *
from openrowset(''MSDASQL''
,''Driver={Microsoft Access Text Driver (*.txt, *.csv)};
DefaultDir='+#FilePath+N'''
,''select * from "'+#FileName+N'"'')
END'
EXEC sp_executesql #SqlStmt;
END
Hint: You can always add PRINT #SQLSTMT to see the code your procedure has generated.
There are two error in the script, both in line:
INSERT INTO dbo.NewTables ('+#TableName+N','+#FileName+N') Values('+#TableName+N','+#FileName+N')
First error: NewTables table must have 2 columns to keep table name and file name. Let's call them COL_TBL, COL_FILE
Second error: You have to add quotes in Values part of statement
Here is how it should look like:
INSERT INTO dbo.NewTables (COL_TBL, COL_FILE) Values('''+#TableName+N''','''+#FileName+N''')
btw, You didn't post code entirely, there is an END at the end missing. Please, next time copy the whole code so others can reproduce the error.
EDIT: Please consider following: using sp_executesql instead of EXEC, to avoid sql injection bugs do not concatenate parameters into dynamic sql and finally check if table exists before truncating it
Try this
IF (NOT EXISTS (SELECT * FROM sys.objects WHERE [type] LIKE 'U' AND name LIKE 'mytable'))
SELECT 'not found';
ELSE
SELECT 'found';