SQL Server : USE instruction in stored procedure - sql-server

I would like to execute this query in a stored procedure, but I get 2 errors :
a database of USE instruction not allowed in a procedure, function, or
a trigger.
Incorrect syntax near the keyword 'CREATE'. (Microsoft SQL
Server, Error: 154).
My code:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[usp_copytable_TEST]
#SourceServer nvarchar(255),
#SourceDatabase nvarchar(255),
#SourceSchema nvarchar(255),
#DestinationSchema nvarchar(255)
AS
BEGIN
SET NOCOUNT ON;
DECLARE
#SQL NVARCHAR(MAX),
#id uniqueidentifier = NEWID()
BEGIN
IF NOT EXISTS (SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'TablesLog_TEST')
CREATE TABLE [dbo].[TablesLog_TEST]
(
[id] [uniqueidentifier] NOT NULL,
[SourceServer] [nvarchar](255) NULL,
[SourceDatabase] [nvarchar](255) NULL,
[SourceSchema] [nvarchar](255) NULL,
[source] [nvarchar](max) NULL,
[destination] [nvarchar](255) NULL,
[timestamp] [datetime] NULL,
[message] [nvarchar](max) NULL,
[type] [smallint] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
INSERT INTO dbo.TablesLog_TEST
SELECT
#id, #SourceServer, #SourceDatabase, #SourceSchema,
'GetAllTables', #DestinationSchema, CURRENT_TIMESTAMP,
'Start Copy', 1
BEGIN TRY
INSERT INTO dbo.TablesLog_TEST
SELECT
#id, #SourceServer, #SourceDatabase, #SourceSchema,
'GetAllTables', #DestinationSchema, CURRENT_TIMESTAMP,
'try 1', 1
-- Create destination schema if it doesn't exist
SELECT #SQL = N'IF NOT EXISTS (SELECT * FROM [' + #SourceDatabase + '].SYS.SCHEMAS WHERE NAME = [' + #DestinationSchema + '])
BEGIN
SELECT #SQL = N'USE ['+ #SourceDatabase +'];
EXEC(''CREATE SCHEMA '+ #DestinationSchema +' '')'
EXEC sp_executesql #SQL
END'
EXEC sp_executesql #SQL
END TRY
BEGIN CATCH
INSERT INTO dbo.TablesLog_TEST
SELECT #id, #SourceServer, #SourceDatabase, #SourceSchema,
'GetAllTables', #DestinationSchema, CURRENT_TIMESTAMP,
'ERROR: ' + ERROR_MESSAGE(), 0
END CATCH
--Return value:
SELECT 1;
END
Someone can help me please?
Best regards
Slim

Slim
This code will work
SELECT #SQL = N'IF NOT EXISTS (SELECT * FROM [' + #SourceDatabase + '].SYS.SCHEMAS WHERE NAME = ''' + #DestinationSchema + ''')
BEGIN
DECLARE #SQL NVARCHAR(MAX);
SELECT #SQL = N''USE ['+ #SourceDatabase +'];
EXEC(''''CREATE SCHEMA '+ #DestinationSchema +' '''')''
EXEC sp_executesql #SQL
END'
EXEC sp_executesql #SQL
As Sandip spotted you need to declare the #SQL variable in your dynamic code. When you use sp_executesql to run the dynamic code, it is effectively running in isolation to your main stored proc, and thus knows nothing about any variables declared previously. You'll see I've added a few more single quotes to get everything working; also replaced the [] in the SELECT statement so that #DestinationSchema appears as text, and not a column name.
As an aside, do you know how to use the debug tools in SQL Server Management Studio? Type the following
EXEC usp_copytable_TEST 'SourceServer', 'SourceDatabase', 'SourceSchema', 'DestinationSchema'
on its own in a new query window. Instead of pressing F5 to execute, press ALT+F5, this will invoke a debug session and you can now step through the code line by line, watch variables and so on. You'll find this very helpful as you can see the values of your dynamic SQL strings.

Try This:
USE [CORE]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Create PROCEDURE [dbo].[usp_copytable_TEST]
#SourceServer nvarchar(255),
#SourceDatabase nvarchar(255),
#SourceSchema nvarchar(255),
#DestinationSchema nvarchar(255)
AS
BEGIN
SET NOCOUNT ON;
DECLARE
#SQL NVARCHAR(MAX),
#id uniqueidentifier = NEWID()
BEGIN
If NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = 'TablesLog_TEST')
CREATE TABLE [dbo].[TablesLog_TEST](
[id] [uniqueidentifier] NOT NULL,
[SourceServer] [nvarchar](255) NULL,
[SourceDatabase] [nvarchar](255) NULL,
[SourceSchema] [nvarchar](255) NULL,
[source] [nvarchar](max) NULL,
[destination] [nvarchar](255) NULL,
[timestamp] [datetime] NULL,
[message] [nvarchar](max) NULL,
[type] [smallint] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
INSERT INTO dbo.TablesLog_TEST SELECT #id, #SourceServer,#SourceDatabase, #SourceSchema, 'GetAllTables', #DestinationSchema, CURRENT_TIMESTAMP, 'Start Copy', 1
BEGIN TRY
INSERT INTO dbo.TablesLog_TEST SELECT #id, #SourceServer,#SourceDatabase, #SourceSchema, 'GetAllTables', #DestinationSchema, CURRENT_TIMESTAMP, 'try 1', 1
-- Create destination schema if it doesn't exist
SELECT #SQL = N'IF NOT EXISTS (SELECT * FROM [' + #SourceDatabase + '].SYS.SCHEMAS WHERE NAME = [' + #DestinationSchema + '])
BEGIN
SELECT #SQL = N''USE ['+ #SourceDatabase +'];
EXEC(''CREATE SCHEMA '+ #DestinationSchema +' '')''
EXEC sp_executesql #SQL
END'
EXEC sp_executesql #SQL
END TRY
BEGIN CATCH
INSERT INTO dbo.TablesLog_TEST SELECT #id, #SourceServer,#SourceDatabase, #SourceSchema, 'GetAllTables', #DestinationSchema, CURRENT_TIMESTAMP, 'ERROR: ' + ERROR_MESSAGE(), 0
END CATCH
--Return value:
SELECT 1;
END
END

You seem to be missing some quotation marks when building your dynamic SQL
Try this
SELECT #SQL = N'IF NOT EXISTS (SELECT * FROM [' + #SourceDatabase + '].SYS.SCHEMAS WHERE NAME = [' + #DestinationSchema + '])
BEGIN
SELECT #SQL = N''USE ['+ #SourceDatabase +'];
EXEC(''CREATE SCHEMA '+ #DestinationSchema +' '')''
EXEC sp_executesql #SQL
END'

Thank you #Sandip Patel for your help,
Thank you Paul Bambury for your help
It work!!!
The problem was missing quotation marks when building my dynamic SQL.
Like this:
--Create Temporary table
SELECT #SQL ='SELECT * INTO SANDBOX.dbo.TempTables FROM OPENQUERY(['+#SourceServer+'],
''
SELECT * FROM ICTNONID.information_schema.tables where TABLE_SCHEMA = '''''+#SourceSchema+'''''
'')
WHERE TABLE_NAME NOT in (SELECT IGNORENAME FROM CORE.dbo.CopyTablesProdIgnore where IGNORETYPE = ''TABLE'' AND schemaname = '''+#SourceSchema+''')
'
EXEC sp_executesql #SQL

Related

Is there a way to store full DDL of View or Procedure definition from another database in separate table

I'm trying to store DDLs of some views and stored procedures in a separate table in the Dump database. There are too many similar databases on the server. But some objects are redundant. They will be listed in the table and then dropped from the database. But their DDLs will be backed up if somebody will need them later.
The procedure works fine when the views are small, but if the size of the code exceeds some value - I'm get an error:
XML parsing: line 120, character 31, incorrect CDATA section syntax
Maybe that's I'm using the dbo.sp_sqlexec procedure, but I'm not sure. Will appreciate any ideas.
Definition of the table where those views will be firstly listed and then stored:
CREATE TABLE [dbo].[ViewList_Explicit]
(
[ID] [int] IDENTITY(1,1) PRIMARY KEY NOT NULL,
[ServerName] [sysname] NOT NULL,
[DatabaseName] [sysname] NOT NULL,
[SchemaName] [sysname] NOT NULL,
[ViewName] [sysname] NOT NULL,
[DefinitionText] [xml] NULL,
[IsTransferred] [bit] NOT NULL,
[DateTransferred] [datetime] NULL
);
INSERT INTO [dbo].[ViewList_Explicit] ([ServerName], [DatabaseName], [SchemaName], [ViewName], [DefinitionText], [IsTransferred], [DateTransferred])
VALUES ('dbserver', 'reco', 'dbo', 'v_redundant_toDrop', NULL, 0, NULL)
This is the code of the procedure:
CREATE OR ALTER PROCEDURE [dbo].[sp_moveViews2Dump]
(#DatabaseName SYSNAME)
AS
BEGIN
SET NOCOUNT ON
DECLARE #Serv SYSNAME = ##SERVERNAME;
DECLARE #SQLstringToDrop NVARCHAR(MAX), #SQLstringForDefinition NVARCHAR(MAX);
DECLARE #SchemaName SYSNAME, #ViewName SYSNAME, #ExplicitID INTEGER;
DECLARE #DDLview XML;
DECLARE #Buffer TABLE(line XML);
DECLARE Schedule_cursor CURSOR LOCAL FOR
SELECT ID, SchemaName, ViewName
FROM [Dump].dbo.ViewList_Explicit
WHERE DatabaseName = #DatabaseName
AND ServerName = #Serv
AND IsTransferred = 0
OPEN Schedule_cursor
FETCH NEXT FROM Schedule_cursor INTO #ExplicitID, #SchemaName, #ViewName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQLstringForDefinition = 'SELECT CONCAT(''<query><![CDATA['', VIEW_DEFINITION, '']]></query>'') FROM ['
+ #DatabaseName + '].INFORMATION_SCHEMA.VIEWS
WHERE TABLE_NAME = '''+ #ViewName + ''' AND TABLE_SCHEMA = ''' + #SchemaName + ''';'
--PRINT #SQLstringForDefinition
INSERT #Buffer EXECUTE dbo.sp_sqlexec #SQLstringForDefinition
SELECT #DDLview = line FROM #Buffer
SELECT #SQLstringToDrop = 'USE [' + #DatabaseName + ']
DROP VIEW IF EXISTS [' + #SchemaName + '].[' + #ViewName + ']'
--EXECUTE dbo.sp_sqlexec #SQLstringToDrop -- Commented out to avoid the deletion
UPDATE [Dump].dbo.ViewList_Explicit
SET [DefinitionText] = #DDLview, IsTransferred = 1, DateTransferred = GETDATE()
WHERE ID = #ExplicitID
DELETE FROM #Buffer
FETCH NEXT FROM Schedule_cursor INTO #ExplicitID, #SchemaName, #ViewName
END
CLOSE Schedule_cursor
DEALLOCATE Schedule_cursor
SET NOCOUNT OFF
END
Not sure why you're storing module definitions as XML but you should be able to do this in one step, without the cursor, unsupported system procedures from decades ago, and INFORMATION_SCHEMA which is generally garbage (<-- see the section on Module Definitions):
DECLARE #exec nvarchar(1024) = QUOTENAME(#DatabaseName)
+ N'.sys.sp_executesql';
DECLARE #sql nvarchar(max) = N';WITH vws AS
(SELECT SchemaName = s.name, ViewName = v.name,
DefinitionText = CONCAT(''<query><![CDATA['',
OBJECT_DEFINITION(v.[object_id]), N'']]></query>'')
FROM sys.schemas AS s
INNER JOIN sys.views AS v
ON s.[schema_id] = v.[schema_id]
)
UPDATE vle
SET vle.DefinitionText = sps.DefinitionText,
vle.IsTransferred = 1,
vle.DateTransferred = GETDATE()
FROM [Dump].dbo.ViewList_Explicit AS vle
INNER JOIN vws
ON vle.SchemaName = vws.SchemaName
AND vle.ViewName = vws.ViewName
WHERE vle.DatabaseName = #db
AND vle.ServerName = ##SERVERNAME
AND vle.IsTransferred = 0;';
EXEC #exec #sql, N'#db sysname', #DatabaseName;
The main problem was mentioned in a comment already: VIEW_DEFINITION is limited to 4,000 characters.
The purpose of #SQLstringToDrop is unclear. If you're on a modern enough version of SQL Server, you could instead inject CREATE OR ALTER into the definition, or generate that only at time of actual execution / deployment ... that doesn't change per view so there's no reason to store the entire IF EXISTS / DROP sequence for each and every view.
If you want to drop the views after you've backed up their definitions (though, really, why you aren't using proper version control system for this is a mystery), you can simply use the same technique (all in one shot instead of in a loop):
DECLARE #exec nvarchar(1024) = QUOTENAME(#DatabaseName)
+ N'.sys.sp_executesql';
DECLARE #sql nvarchar(max) = N'';
SELECT #sql += CONCAT(N'DROP VIEW IF EXISTS ',
QUOTENAME(SchemaName), N'.',
QUOTENAME(ViewName), N';')
FROM [Dump].dbo.ViewList_Explicit
WHERE DatabaseName = #DatabaseName
AND ServerName = ##SERVERNAME;
EXEC #exec #sql;
As an additional tip, don't ever put square brackets around names manually (e.g. [' + #SchemaName + ']) - this does not protect you against SQL injection. And while it's unlikely someone put nefarious object names into the system you're working against now, it sets a bad example.

SQL Server Stored Procedure for multiple excel file load [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
Please help me is their procedure available to use for multiple Excel files load into SQL Server table.
I found one on google, but not working as expected:
Msg 111, Level 15, State 1, Procedure usp_ImportMultipleFiles, Line 11 [Batch Start Line 40]
'CREATE/ALTER PROCEDURE' must be the first statement in a query batch.
Msg 137, Level 15, State 2, Line 67
Must declare the scalar variable "#filepath".
1a. Create a table for getting file names
IF EXISTS (SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = '[FileNames]')
DROP TABLE [FileNames];
CREATE TABLE [dbo].[FileNames]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](200) NULL
) ON [PRIMARY]
IF EXISTS (SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = '[MultipleXLtoSQL_stage]')
DROP TABLE MultipleXLtoSQL_stage;
CREATE TABLE [dbo].[MultipleXLtoSQL_stage]
(
[Sno] [float] NULL,
[EmpID] [float] NULL,
[EmpName] [nvarchar](255) NULL,
[Checkin] [datetime] NULL,
[Checkout] [datetime] NULL,
[Working hours] [float] NULL,
[Status] [nvarchar](255) NULL
) ON [PRIMARY]
IF EXISTS (SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = '[MultipleXLtoSQL]')
DROP TABLE MultipleXLtoSQL;
CREATE TABLE [dbo].[MultipleXLtoSQL]
(
[Sno] [float] NULL,
[EmpID] [float] NULL,
[EmpName] [nvarchar](255) NULL,
[Checkin] [datetime] NULL,
[Checkout] [datetime] NULL,
[Working hours] [float] NULL,
[Status] [nvarchar](255) NULL,
[File_name] [varchar](50) NULL,
[date] [date] NULL
) ON [PRIMARY]
/* —————————————————————–
2a. Create a stored procedure for getting the file count
—————————————————————–*/
IF EXISTS (SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[usp_ImportMultipleFiles]’)
AND type IN (N’P’, N’PC’))
DROP PROCEDURE [dbo].[usp_ImportMultipleFiles]
CREATE PROCEDURE [dbo].[usp_ImportMultipleFiles]
#filepath varchar(500),
#pattern varchar(100),
#TableName varchar(128) = NULL
AS
SET QUOTED_IDENTIFIER OFF
DECLARE #query varchar(1000)
DECLARE #max1 int
DECLARE #count1 int
DECLARE #filename varchar(100)
SET #count1 = 0
DROP TABLE [FileNames]
CREATE TABLE #x (name varchar(200))
SET #query = ‘master.dbo.xp_cmdshell “dir ‘ + #filepath + #pattern + ‘ /b”‘
INSERT #x
EXEC (#query)
DELETE FROM #x
WHERE name IS NULL
SELECT
IDENTITY(int, 1, 1) AS ID,
name INTO [FileNames]
FROM #x
DROP TABLE #x
/*—————————————————————————-
2b. Create a stored procedure for inserting the excel files one by one
—————————————————————————-*/
IF EXISTS (SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[Article_InsertMultiplexlFile]')
AND type IN (N'P', N'PC'))
DROP PROCEDURE [Article_InsertMultiplexlFile];
CREATE PROCEDURE [dbo].[Article_InsertMultiplexlFile]
(#filepath varchar(max),
#table_name varchar(50) = NULL)
AS
BEGIN
DECLARE #v_filepath varchar(max),
#v_delete varchar(500),
#v_closebracket varchar(10),
#max1 int, #count1 int,
#filename varchar(100),
#v_message varchar(50),
#v_Date date,
#v_filename varchar(48),
#v_sheetname varchar(500);
SET #count1 = 0;
SET #v_closebracket = ')';
SET #v_sheetname = 'Sheet1'
EXEC usp_ImportMultipleFiles #filepath, '*.x*'
SET #max1 = (SELECT MAX(ID)
FROM [FileNames])
--print #max1
--print #count1
WHILE #count1 <= #max1
BEGIN
SET #count1 = #count1 + 1
SET #filename = NULL
SET #filename = (SELECT name
FROM [FileNames]
WHERE [id] = #count1)
IF #filename IS NOT NULL
BEGIN
BEGIN TRY
SET #v_filepath = 'INSERT INTO ' + #table_name + '
SELECT * FROM OPENROWSET(' + '''' + 'Microsoft.ACE.OLEDB.12.0' + '''' + ',' + '''' +
'Excel 12.0;Database=' + #filepath + #filename + '''' + ',' + '''' + 'SELECT * FROM [' + #v_sheetname + '$]''' + #v_closebracket
EXEC (#v_filepath)
End Try
BEGIN CATCH
SELECT
'ERROR WITH Filename #filename = ' + #filename + ' ' + ERROR_MESSAGE() AS Error_Description
END CATCH
End --End if
SET #v_date = CAST(SUBSTRING(#filename, 1, 10) AS date)
INSERT INTO MultipleXLtoSQL ([Date], [Sno], [EmpID], [EmpName], [Checkin], [Checkout], [Working hours], [Status], [File_name])
SELECT
#v_date,
[Sno],
[EmpID],
[EmpName],
[Checkin],
[Checkout],
[Working hours],
[Status],
#filename
FROM MultipleXLtoSQL_stage
Truncate table MultipleXLtoSQL_stage
End
--While
End
/*—————————————————————————-
Execute the Stored Procedure (Give the folder path)
—————————————————————————-*/
EXEC [dbo].[Article_InsertMultiplexlFile] 'D:\MultipleExcel2SQL\ArticleInputFiles\',
'MultipleXLtoSQL_stage'
/*—————————————————————————-
4a. To see how many records were imported and from which file (Query 1)
—————————————————————————-*/
SELECT
FILE_NAME,
COUNT(*) No_of_Records
FROM MultipleXLtoSQL
GROUP BY FILE_NAME;
/*—————————————————————————-
4b. To see all the records from table MultipleXLtoSQL (Query 2)
—————————————————————————-*/
SELECT
[Date],
[Sno],
[EmpID],
[EmpName],
[Working hours],
[Status],
[File_name]
FROM MultipleXLtoSQL;
/*—————————————————————————-
4c. To see total number of present and absent days (Query 3)
—————————————————————————-*/
SELECT
Empname,
COUNT(status) PRESENT_DAYS,
0 ABSENT_DAYS
FROM MultipleXLtoSQL
WHERE status = 'Present'
GROUP BY Empname UNION SELECT
Empname,
0,
COUNT(status) ABSENT_DAYS
FROM MultipleXLtoSQL
WHERE status = 'Absent'
GROUP BY Empname
/*—————————————————————————-
4d. To see the details of a selected employee (Query 4)
—————————————————————————-*/
SELECT
[Date],
[Sno],
[EmpID],
[EmpName],
[Working hours],
[Status],
[File_name]
FROM MultipleXLtoSQL
WHERE Empname = 'A'
/*—————————————————————————-
–To access the files in folders
—————————————————————————-*/
/*
SET ANSI_PADDING OFF
GO
EXEC sp_configure 'show advanced options',
1
reconfigure with override
GO
EXEC sp_configure 'xp_cmdshell',
1
reconfigure with override
GO
*/
I see two errors here:
'CREATE/ALTER PROCEDURE' must be the first statement in a query batch.
Must declare the scalar variable "#filepath".
Get a very simple script to work, and then build on that. Can you try it like this?
insert into test.dbo.Categories
SELECT * FROM OPENROWSET('Microsoft.ACE.OLEDB.12.0','Excel 12.0;
Database=C:\Users\Excel\Desktop\Book1.xls;
HDR=yes','Select * from [Sheet1$]')

Use null result of exec sp_execute

I have some dynamic SQL that I use to see if a certain property for a certain client is in a table. If so, it will return the value, if not, it will return null. However, I would like it to return a default value if the property is not found.
The table:
CREATE TABLE [test].[customers](
[customer] [nvarchar](256) NULL,
[key_name] [nvarchar](256) NULL,
[key_value] [nvarchar](256) NULL
)
GO
INSERT INTO [test].[customers]
([customer]
,[key_name]
,[key_value])
VALUES
('JohnDoe'
,'periodlength'
,'3')
GO
The Dynamic SQL:
declare #customer as nvarchar(256) = 'JohnDoe'
declare #table as nvarchar(256) = 'test.customers'
declare #sql as nvarchar(4000)
set #sql = 'select [key_value] from ' + #table + ' where [key_name]= ''periodlength'' and customer= ''' + #customer + ''''
exec sp_executesql #sql
So when Qqerying for John Doe you get result 3 which is perfect. However, I would like to reurn 1 for Jane Doe. So I was thinking along the lines
IF exec sp_executesql #sql IS NULL 1 ELSE exec sp_executesql #sql
but that doesn't work.
How to change my dynamic query so that is returns a default value if the property is not found?
Could you try the following query but this usage only return a single value;
declare #customer as nvarchar(256) = 'JohnDoe'
declare #table as nvarchar(256) = 'test.customers'
DECLARE #ValReturn nvarchar(50)
declare #sql as nvarchar(4000)
set #sql = 'select #ValOutPut=[key_value] from ' + #table + ' where [key_name]= ''periodlength'' and customer= ''' + #customer + ''''
exec sp_executesql #sql , N'#ValOutPut nvarchar(25) OUTPUT' ,#ValOutPut = #ValReturn OUTPUT
BEGIN
IF #ValReturn IS NULL
SELECT NULL
ELSE
SELECT #ValReturn
END

Importing Date data from csv file using bulk insert in SQL Server

I am having trouble importing date data into SQL Server from a csv file using bulk insert.
I'm using the following stored procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[usp_ImportTestData]
#Filepath varchar(500),
#Pattern varchar(100),
#TableName varchar(128),
#ViewName varchar(128),
#ResetTable bit = 0
AS
SET QUOTED_IDENTIFIER OFF
DECLARE #query varchar(1000)
DECLARE #numfiles int
DECLARE #filename varchar(100)
DECLARE #files TABLE (Name varchar(200) NULL)
--Delete the contents of the rawData table and let the user know
IF #ResetTable = 1
BEGIN
PRINT 'Emptying table [' + #TableName + ']...'
EXEC ('DELETE ' + #TableName)
END
--Pull a list of the CSV file names from the folder that they're stored in
SET #query ='master.dbo.xp_cmdshell "dir '+#filepath+#pattern +' /b"'
INSERT #files(Name)
EXEC (#query)
DECLARE curs_files CURSOR FOR
SELECT Name
FROM #files
WHERE Name IS NOT NULL
--For each CSV file, execute a query
SET #numfiles = 0
OPEN curs_files
FETCH NEXT FROM curs_files INTO #filename
WHILE (##FETCH_STATUS = 0)
BEGIN
SET #numfiles += 1
-- BULK INSERT each CSV file into the rawData view and update the rawData
-- table with the file name and the upload datetime
SET #query = ('BULK INSERT ' + #ViewName + ' FROM ''' + #Filepath+#filename + ''' WITH(FIRSTROW = 2, FIELDTERMINATOR='','', ROWTERMINATOR=''\n'');'
+ ' UPDATE ' + #TableName
+ ' SET [FileName] = ' + '''' + #filename + ''''
+ ' WHERE [FileName] Is Null;'
+ ' UPDATE ' + #TableName
+ ' SET [UploadDatetime] = ' + '''' + CAST(GETDATE() as nvarchar(1000)) + ''''
+ ' WHERE [UploadDatetime] Is Null;'
)
PRINT 'Importing [' + #filename + '] into [' + #TableName + ']...'
EXEC (#query)
FETCH NEXT FROM curs_files INTO #filename
END
CLOSE curs_files
DEALLOCATE curs_files
Please note I got this code from http://www.decisivedata.net/blog/import-data-from-multiple-csv-files-using-bulk-insert.
This is my table:
[dbo].[Test]
(
[Money] [float] NULL,
[Amount] [varchar](50) NULL,
[Date] [datetime] NULL,
[DataID] [int] IDENTITY(1,1) NOT NULL,
[FileName] [varchar](50) NULL,
[UploadDatetime] [datetime] NULL
)
This is my view
SELECT Money, Amount, Date
FROM dbo.Test
Here is a sample of one of my csv files:
Money, Amount, Date,
1043333333.5,4, 01/29/2018
57,4, 01/29/2018
604,3,01/29/2018
Here is my query:
EXEC usp_ImportTestData
#filepath = 'C:\TestDataCSV\',
#pattern = '*.csv',
#TableName = 'Test',
#ViewName = 'V_Test',
#ResetTable = 1
When I run the query I get this error message
Bulk load data conversion error (type mismatch or invalid character for the specified codepage) for row 3, column 3 (Date)
I have no idea what is wrong! If I try to do a straight bulk insert for just one file it doesn't seem to have any trouble with the date field. If I get rid of the date column it seems to work fine too..
If that is your actual data you posted, note that there is a space included with the date.
Also, not part of your question, avoid FLOAT and REAL data types unless you are counting the number of inches between planets. Those data types are only for numbers that have estimates because they are so big.

Stored procedure with table name and values as parameters

I have problems for insert values with a stored procedure with values as parameters and table name too. this is part of my table:
My table:
CREATE TABLE [dbo].[INGRESOLOTEMP_100]
(
[CLIENTE_CODIGO] [SMALLINT] NOT NULL,
[CAJA_CODIGO] [nvarchar](20) NULL,
[CAJA_NUMERO] [SMALLINT] NOT NULL,
)
My stored procedure:
CREATE PROCEDURE [dbo].[SP_LOT_INSERTLOTEMP]
#IDENT_TABLA NVARCHAR(10),
#CLIENTE_CODIGO SMALLINT,
#CAJA_CODIGO NVARCHAR(15),
#CAJA_NUMERO SMALLINT
AS
DECLARE #NOMBRE_TABLA NVARCHAR(40)
SELECT
#NOMBRE_TABLA = 'INGRESOLOTEMP_' + CONVERT(VARCHAR(100), #IDENT_TABLA)
SELECT
#CAJA_CODIGO = CONVERT(VARCHAR(20), #CAJA_CODIGO)
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = 'INSERT into dbo.' + quotename(#NOMBRE_TABLA) +
' (CLIENTE_CODIGO, CAJA_CODIGO, CAJA_NUMERO) VALUES (' +
CONVERT(VARCHAR(20),#CLIENTE_CODIGO) + ',' + #CAJA_CODIGO + ',' +
CONVERT(VARCHAR(20),#CAJA_NUMERO) +
')'
EXEC sp_executesql #SQL
My table name is formed by a table name + an Id (every user has one)
But the problem is when I execute the stored procedure:
SP_LOT_INSERTLOTEMP 100, 123, 'uio123', 1
I have an error in SQL with value: 'uio123'
But if I execute:
SP_LOT_INSERTLOTEMP 100, 123, 80, 1
The insert is perfect, The problem is that I need insert numeric and text values, even date time values too. I realized varchar conversions in the stored procedure, but I don't get it yet.
Anyone, have an Idea?
Please I hope you can help me.
Gregg, Giorgi...
Thanks, I followed your advices, I think I get it:
ALTER PROCEDURE [dbo].[SP_LOT_INSERTLOTEMP]
#IDENT_TABLA NVARCHAR(10),
#CLIENTE_CODIGO SMALLINT,
#CAJA_CODIGO NVARCHAR(15),
#CAJA_NUMERO SMALLINT
AS
BEGIN
DECLARE #NOMBRE_TABLA NVARCHAR(40)
SELECT #NOMBRE_TABLA = 'INGRESOLOTEMP_' + CONVERT(VARCHAR(100),#IDENT_TABLA)
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = 'INSERT into dbo.' + #NOMBRE_TABLA
SET #SQL += '(CLIENTE_CODIGO, CAJA_CODIGO, CAJA_NUMERO) VALUES ('
SET #SQL += CONVERT(VARCHAR(20), #CLIENTE_CODIGO) + ', '
SET #SQL += '''' + CONVERT(VARCHAR(20), #CAJA_CODIGO) + ''', '
SET #SQL += CONVERT(VARCHAR(20), #CAJA_NUMERO) + ')'
DECLARE #ParmDefinition nvarchar(500)
SET #ParmDefinition = '#IDENT_TABLA NVARCHAR(10), #CLIENTE_CODIGO SMALLINT, #CAJA_CODIGO NVARCHAR(15), #CAJA_NUMERO SMALLINT'
SELECT #sql
PRINT #sql
EXEC sp_executesql #SQL, #ParmDefinition, #IDENT_TABLA, #CLIENTE_CODIGO, #CAJA_CODIGO, #CAJA_NUMERO
END
And when I print what execution contains:
EXEC [SP_LOT_INSERTLOTEMP] 100, 123, 'UIO123', 6
I have this:
INSERT into dbo.INGRESOLOTEMP_100(CLIENTE_CODIGO, CAJA_CODIGO, CAJA_NUMERO) VALUES (123, 'UIO123', 6)
I will continue, If I have any question, I hope somebody or you, can help me.
Thanks.
The problem is in varchar column. Notice the generated statements for
EXEC SP_LOT_INSERTLOTEMP 100, 123, 'uio123', 1
EXEC SP_LOT_INSERTLOTEMP 100, 123, 80, 1
INSERT into dbo.[INGRESOLOTEMP_100] (CLIENTE_CODIGO, CAJA_CODIGO, CAJA_NUMERO) VALUES (123,uio123,1)
INSERT into dbo.[INGRESOLOTEMP_100] (CLIENTE_CODIGO, CAJA_CODIGO, CAJA_NUMERO) VALUES (123,80,1)
Try uncommenting --PRINT #SQL and see yourself the resulting statements.
You should provide additional quotes. Try this:
ALTER PROCEDURE [dbo].[SP_LOT_INSERTLOTEMP]
#IDENT_TABLA NVARCHAR(10),
#CLIENTE_CODIGO SMALLINT,
#CAJA_CODIGO NVARCHAR(15),
#CAJA_NUMERO SMALLINT
AS
DECLARE #NOMBRE_TABLA NVARCHAR(40)
SELECT #NOMBRE_TABLA = 'INGRESOLOTEMP_' + CONVERT(VARCHAR(100),#IDENT_TABLA)
SELECT #CAJA_CODIGO = CONVERT(VARCHAR(20), #CAJA_CODIGO)
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = 'INSERT into dbo.' + quotename(#NOMBRE_TABLA) +
' (CLIENTE_CODIGO, CAJA_CODIGO, CAJA_NUMERO) VALUES (' +
+ CONVERT(VARCHAR(20),#CLIENTE_CODIGO) +','''/*changes here*/ + #CAJA_CODIGO + ''','/*changes here*/ +
CONVERT(VARCHAR(20),#CAJA_NUMERO) +
')'
--PRINT #SQL
EXEC sp_executesql #SQL
Several changes needed to be made to your procedure; see below:
ALTER PROCEDURE [dbo].[SP_LOT_INSERTLOTEMP]
#IDENT_TABLA NVARCHAR(10),
#CLIENTE_CODIGO SMALLINT,
#CAJA_CODIGO NVARCHAR(15),
#CAJA_NUMERO SMALLINT
AS
BEGIN
DECLARE #NOMBRE_TABLA NVARCHAR(40)
SELECT #NOMBRE_TABLA = 'INGRESOLOTEMP_' + CONVERT(VARCHAR(100),#IDENT_TABLA)
SELECT #CAJA_CODIGO = CONVERT(VARCHAR(20), #CAJA_CODIGO)
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = 'INSERT into dbo.' + #NOMBRE_TABLA
SET #SQL += '(CLIENTE_CODIGO, CAJA_CODIGO, CAJA_NUMERO)
VALUES (#CLIENTE_CODIGO, #CAJA_CODIGO, #CAJA_NUMERO)'
DECLARE #ParmDefinition nvarchar(500)
SET #ParmDefinition = '#IDENT_TABLA NVARCHAR(10), #CLIENTE_CODIGO SMALLINT, #CAJA_CODIGO NVARCHAR(15), #CAJA_NUMERO SMALLINT'
SELECT #sql
EXEC sp_executesql #SQL, #ParmDefinition, #IDENT_TABLA, #CLIENTE_CODIGO, #CAJA_CODIGO, #CAJA_NUMERO
END

Resources