Executing TSQL batch multiple times through dynamic sql - sql-server

I'm using SQL SERVER 2017 (Developper Edition 64 Bit) on a Windows 10 Machine. I'm trying to execute in a dynamic sql a batch multiples times through GO and it won't work.
But the sql Statement will work if it is not execute dynamically. The goal is to do it dynamically and I still don't figure out what I am doing wrong.
Here is how the definition tables look like:
ParentTable
(
Id uniqueidentifier DEFAULT (newsequentialid()) not null,
Created datetime not null,
Creator uniqueidentifier not null,
Modifier uniqueidentifier null,
Modified datetime null
)
ChildTable
(
Id uniqueidentifier DEFAULT (newsequentialid()) not null,
ParentTable_Id not null,
Created datetime not null,
Creator uniqueidentifier not null,
Modifier uniqueidentifier null,
Modified datetime null
)
This is what I've tried so far:
create Procedure InsertIntoChildTable
AS
BEGIN
DECLARE #countDset int
DECLARE #todaysdate datetime
DECLARE #UserName uniqueidentifier
DECLARE #ParentTable_Id uniqueidentifier
DECLARE #insertIntoChildTable nvarchar(max)
DECLARE #ChildTableName nvarchar(35)
SET #ChildTableName = ChildTable
SET #countDset = 6
SET #todaysdate = GETDATE()
SET #UserName = 'e86aacf4-9887-e911-9724-4439c492b2a7'
BEGIN TRY
BEGIN TRANSACTION
SET #insertIntoChildTable = 'INSERT INTO ' + #ChildTableName + '
(ParentTable_Id, Created, Creator, Modified, Modifier)
VALUES ( (select max(Id) from ParentTable) , #todaysdate, #UserName ,
NULL, NULL) ' + ' GO ' + #countDset
EXECUTE sp_executesql #insertIntoChildTable,N'#ChildTableName
nvarchar(35), #todaysdate datetime, #UserName uniqueidentifier,
#countDset int', #ChildTableName = #ChildTableName, #todaysdate =
#todaysdate, #UserName = #UserName, #countDset = #countDset
COMMIT TRANSACTION
END TRY
BEGIN CATCH
PRINT 'Could not insert in the Child table'
ROLLBACK TRANSACTION
RETURN
END CATCH
END
After the Line with 'Go ' + #countDset it will automatically go into the Catch block and return.
Thank you

INSERT INTO ChildTable ( ParentTable_Id, Created, Creator, Modified, Modifier )
SELECT (select max(Id) from ParentTable) as ParentId , #todaysdate, #UserName ,
NULL, NULL
FROM
(
SELECT TOP #countDset '' As Dummy
FROM sys.Objects As A
CROSS JOIN sys.Objects As B
) As Multiplier
Guided through the example Zohar posted I could insert new Rows in the ChildTable using CROSS JOIN

Related

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$]')

Conversion Failure In Stored Procedure But Not In SSMS

I am working on a script in a stored procedure to insert a new line that includes a getdate() value, and then select the line that has that same getdate() value. In practice, my classic ASP page will call one stored procedure after the other (the first being an insert, the next, the select).
When I construct these two queries in SQL Server Mgmt Studio, they work fine; however, once I put them into stored procedures, the select stored procedure throws an error
Conversion failed when converting date and/or time from character string
I'm not sure where the "character string" is, though, unless it is a reference to the dynamic SQL string.
Thanks for any leads. I've posted code below.
Here is the code I use in Mgmt Studio query, which works:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[001_test]
(
[ID] [INT] IDENTITY(1,1) NOT NULL,
[name] [NVARCHAR](50) NULL,
[dateadded] [DATETIME] NULL
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[001_test] ON
INSERT INTO [dbo].[001_test] ([ID], [name], [dateadded])
VALUES (1, N'toot', NULL), (2, N'hickory', NULL),
(3, N'orange', NULL)
SET IDENTITY_INSERT [dbo].[001_test] OFF
INSERT INTO [dbo].[001_test] ([name], [dateadded])
VALUES ('boy', GETDATE())
SELECT
[ID], [name], [dateadded]
FROM
[dbo].[001_test]
WHERE
dateadded = GETDATE()
GO
Here is the insert stored procedure, which does not throw the error. It performs the insert successfully:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[001_test_insert]
#Name VARCHAR(50)
AS
DECLARE #sql NVARCHAR(4000)
SELECT #sql = ' INSERT INTO [001_test] ([name], [dateadded])' +
' VALUES (#Name, GETDATE());'
EXEC sp_executesql #sql, N'#Name VARCHAR(50)', #Name
Here is the stored procedure that is throwing the error (in practice, this stored procedure would be called from a classic ASP page, just after the insert stored procedure). Would the GETDATE() need to be cast for the datetime datatype?
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[001_test_select]
AS
SET NOCOUNT OFF
DECLARE #sql NVARCHAR(4000)
SELECT #sql = ' SELECT ID, Name, dateadded ' +
' FROM [001_test]' +
' WHERE dateadded = ' + GETDATE() + ';'
EXEC sp_executesql #sql
Because you are using dynamic sql, and you can't concat the string with the datetime returned by getdate(). You can define a parameter in your dynamic sql:
DECLARE #current_dt datetime = getdate();
SELECT #sql = ' SELECT ' +
' ID ' +
' ,Name ' +
' ,dateadded ' +
' FROM [001_test]' +
' WHERE ' +
' dateadded = #current_dt';
EXEC sp_executesql #sql, '#current_dt datetime', #current_dt;
You don't need dynamic sql here at all. I would simplify this procedure and remove the complication when it isn't needed. Something like this.
CREATE PROCEDURE [dbo].[001_test_insert]
(
#Name varchar(50)
) AS
set nocount on;
INSERT INTO [001_test]
(
[name]
,[dateadded]
)
VALUES
(
#Name
, getdate()
)

SQL Server create database dynamically and use the database in the script

I have a script that can be represented by the following:
DECLARE #DatabaseNamePart VARCHAR(50) = 'Part1'
DECLARE #DataBaseName VARCHAR(70) = 'MyDataBase_' + #DatabaseNamePart
IF NOT EXISTS (SELECT * FROM master..sysdatabases WHERE [name] = #DataBaseName) BEGIN
DECLARE #SqlQuery NVARCHAR(150) = 'CREATE DATABASE ' + #DataBaseName
EXECUTE (#SqlQuery)
END
DECLARE #UseDatabase NVARCHAR(150) = 'USE ' + #DataBaseName
EXECUTE ( #UseDatabase )
/**************************************************************************/
/* CREATE TABLES */
/**************************************************************************/
IF NOT EXISTS (SELECT * FROM sysobjects WHERE [name]='MyTable' AND xtype='U') BEGIN
CREATE TABLE MyTable (
[id] INT PRIMARY KEY NOT NULL IDENTITY,
[Name] VARCHAR(150) NOT NULL,
)
END
The problem is when I create the table after it's not created in the new database but in whatever database I am currently on.
Any idea on how to use a database that you just created and don't know the name in advance?
DECLARE #DatabaseNamePart VARCHAR(50) = 'Part1'
DECLARE #DataBaseName VARCHAR(70) = 'MyDataBase_' + #DatabaseNamePart
IF NOT EXISTS (SELECT * FROM master..sysdatabases WHERE [name] = #DataBaseName) BEGIN
DECLARE #SqlQuery NVARCHAR(150) = 'CREATE DATABASE ' + #DataBaseName
EXECUTE (#SqlQuery)
END
-- code edited - declaring a new variable and setting the dbname
Declare #newDBName VARCHAR(30)
SET #DBName = #DataBaseName
exec('USE '+ #DBName)
-- code edited
--Create tables query
IF NOT EXISTS (SELECT * FROM sysobjects WHERE [name]='MyTable' AND xtype='U') BEGIN
CREATE TABLE MyTable (
[id] INT PRIMARY KEY NOT NULL IDENTITY,
[Name] VARCHAR(150) NOT NULL,
)
END

BULK Insert Fails with different files sizes

I have this problem where bulk insert fails with different files sizes, specifically, the first file would contain 433 rows while the second file has 2 rows only. But when I insert the 2 rowed file by itself, there's no error.
I have this as my bulk insert statement
set #sql = 'BULK INSERT #temptable
FROM '''+#location+'''
WITH
(
FIELDTERMINATOR = '','',
ROWTERMINATOR = ''\n'',
MAXERRORS = 100,
TABLOCK,
FIRSTROW = 2
)'
The above statement is contained in a stored procedure.
For more information, I will put my stored procedure here.
USE [THERMOWAVE]
GO
/****** Object: StoredProcedure [dbo].[UploadOmronData] Script Date: 02/13/2017 13:48:54 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[UploadOmronData]
#location as nvarchar(max)
as
begin
declare #sql as nvarchar(max)
-- give #location data from VB.net
--declare #location as varchar(max)
--set #location = 'C:\Users\jsumgo\Documents\Visual Studio 2010\Projects\TestUploader\TestUploader\bin\Debug\12320161428420dataUpload.csv'
-- Joshua Magsino 11/28/2016
-- TSql to upload dynamic column data source
--before uploading, make sure that datasource table columns are named equal to database table column
--Check if data is to be stored as reference or could be destroyed
--Check database to store and columns that would be affected
--set configurations to enable Ad Hoc Distributed Queries
/*
sp_configure 'show advanced options', 1;
RECONFIGURE;
GO
sp_configure 'Ad Hoc Distributed Queries', 1;
RECONFIGURE;
GO
*/
-- configure SQL to execute Ad Hoc Queries using MSOFFICE 2010
/*
USE [master]
GO
EXEC master.dbo.sp_MSset_oledb_prop N'Microsoft.ACE.OLEDB.12.0', N'AllowInProcess', 1
GO
EXEC master.dbo.sp_MSset_oledb_prop N'Microsoft.ACE.OLEDB.12.0', N'DynamicParameters', 1
GO
*/
-- fill temptable with data
---------------------------------------------------------------------------------------------------------------
--drop table #temptable
--create blank temptable
create table #temptable
(
[Number] Varchar(20)
)
--declare #sql as varchar(max)
declare #cursor CURSOR
declare #colname as nvarchar(30)
SET #cursor = CURSOR FOR
(Select colname from dbo.sorting)
OPEN #cursor
FETCH NEXT
FROM #cursor INTO #colname
WHILE ##FETCH_STATUS = 0
BEGIN
-- add from column 2 to end
if #colname <> 'Number'
begin
set #sql = 'ALTER TABLE #temptable ADD ['+#colName+'] NVARCHAR(max) NULL'
EXEC sp_executesql #sql, N'#colname nvarchar(max)', #colname
end
FETCH NEXT
FROM #cursor INTO #colName
END
CLOSE #cursor
DEALLOCATE #cursor
---------------------------------------------------------------------------------------------------------------
--declare #location as varchar(max)
--set #location = 'D:\Omron Data\Data\sample\asdasdasdasdasd - Copy.csv'
--declare #sql as varchar(max)
--Insert Data from CSV file to Temptable
set #sql = 'BULK INSERT #temptable
FROM '''+#location+'''
WITH
(
FIELDTERMINATOR = '','',
ROWTERMINATOR = ''\n'',
MAXERRORS = 100,
TABLOCK,
FIRSTROW = 2
)'
EXEC sp_executesql #sql, N'#location as nvarchar(max)', #location
--Insert Statement
--If the location of the new column is in the last column of the CSV file, then direct bulk insert
--safe solution is to insert based on the column name of each table
--cursor is needed
DECLARE #DBcursor CURSOR
DECLARE #DBColname as varchar(30)
DECLARE #DBCOL as nvarchar(max)
--Get Table Names from dbo.sorting
--since all table names are inserted from dbo.sorting, get column names from dbo.sorting
SET #DBcursor = CURSOR FOR
(Select colname from dbo.sorting)
OPEN #DBcursor
FETCH NEXT
FROM #DBcursor INTO #DBColname
WHILE ##FETCH_STATUS = 0
BEGIN
--assemble columns
set #DBCOL = (isnull(#DBCOL,''))+'['+ #DBColname +'],'
FETCH NEXT
FROM #DBcursor INTO #DBColname
END
CLOSE #DBcursor
DEALLOCATE #DBcursor
--remove last (,) from columns
set #DBCOL =LEFT(#DBCOL, LEN(#DBCOL) - 1)
--insert data from temptable to DataUpload
set #sql = 'insert into DataToUpload ('+#DBCOL+') select '+#DBCOL+' from #tempTable'
EXEC sp_executesql #sql,N'#DBCOL NVARCHAR(max)', #DBCOL
--Put BatchID for DataUpload
--BatchId format,Batch + Number(000) + year + month + day
declare #number as nvarchar(max)
set #number = RIGHT('000' +CAST((select ISNULL(max(case when BatchID = null or BatchID = '' then '000' else right(SUBSTRING(BatchID,1,8),3)+ 1 end),'000') from DataToUpload)AS VARCHAR(3)),3)
set #sql = 'update DataToUpload set BatchID = ''Batch'+cast(#number as varchar(max))+cast(year(getdate()) as varchar(4))+''+cast(MONTH(getdate())as varchar(2))+''+cast(DAY(getdate())as varchar(2)) +''' where BatchID is null'
EXEC sp_executesql #sql,N'#number NVARCHAR(max)', #number
--select * from DataToUpload order by BAtchID,Number asc
--select * from dbo.Sorting
--select * from temptable
--delete from DataToUpload
--clear dbo.sorting
delete from dbo.Sorting
--remove temptable
drop table #temptable
DBCC FREEPROCCACHE WITH NO_INFOMSGS;
end
and then the command in a vb.net system that fires the stored procedure through here.
Sub UploadOmronData(ByVal location As String)
'SQL Stored Procedure -- Save data from CSV file to SQL
Dim sqlcom As New SqlClient.SqlCommand
Try
With sqlcom
conn.Open()
.Connection = conn
.CommandTimeout = 100
.CommandText = "dbo.UploadOmronData"
.CommandType = CommandType.StoredProcedure
.Parameters.AddWithValue("#location", location)
.ExecuteReader()
End With
Catch ex As Exception
MsgBox(ex.Message + " " + location)
GC.Collect()
sqlcom.Dispose()
frmMain.Close()
End Try
conn.Close()
sqlcom.Dispose()
GC.Collect()
End Sub
And the error message which I receive:
Bulk load data conversion error (truncation) for row 2, column 1 (Number).
Bulk load data conversion error (truncation) for row 3, column 1 (Number).
ADDED INFORMATION
Here is the table structure of dbo.DataToUpload
CREATE TABLE [dbo].[DataToUpload](
[Number] [int] NULL,
[Date&Time] [nvarchar](max) NULL,
[ms] [nvarchar](50) NULL,
[CH34] [nvarchar](50) NULL,
[CH35] [nvarchar](50) NULL,
[CH36] [nvarchar](50) NULL,
[CH37] [nvarchar](50) NULL,
[CH38] [nvarchar](50) NULL,
[CH39] [nvarchar](50) NULL,
[Alarm1-10] [nvarchar](50) NULL,
[Alarm11-20] [nvarchar](50) NULL,
[Alarm21-30] [nvarchar](50) NULL,
[Alarm31-40] [nvarchar](50) NULL,
[AlarmOut] [nvarchar](50) NULL,
[BatchID] [nvarchar](50) NULL,
[CH31] [nvarchar](20) NULL,
[CH32] [nvarchar](20) NULL,
[CH33] [nvarchar](20) NULL
) ON [PRIMARY]
and the rows that I'm trying to insert
Number,Date&Time,ms,CH34,CH35,CH36,CH37,CH38,CH39,Alarm1-10,Alarm11-20,Alarm21-30,Alarm31-40,AlarmOut
1,2016-08-08 16:23:16,000,+61.2,+64.0,+35.4,+94.4,+185.4,+151.2,LLLLLLLLLL,LLLLLLLLLL,LLLLLLLLLL,LLLLLLLLLL,LLLL
2,2016-08-08 16:23:26,000,+61.1,+64.4,+35.4,+94.3,+185.4,+151.2,LLLLLLLLLL,LLLLLLLLLL,LLLLLLLLLL,LLLLLLLLLL,LLLL
and If it mayhelp, the system I created is a background worker, since I have to run the code always.
I reckon the cause is that you're asking BULK INSERT to load 14 columns of data, but you're importing into #TempTable which doesn't have enough fields in it.
Your code creates a #tempTable table, and you use a CURSOR to add extra fields to it... but I reckon the end result isn't a table with 14 fields in it.
Before your BULK INSERT #temptable command gets run, how many fields are in the #temptable table ?
For example, if you just had one field in this table, when you ran the bulk-insert it would insist on trying to import the entire row into that one field, complete with all the commas, but, of course, it doesn't fit in a 20-character string.
CREATE TABLE #temptable
(
[Number] VARCHAR(20)
)
The solution... simply change your temporary table to have the correct number of columns, and the BULK INSERT will work fine:
CREATE TABLE #temptable
(
[Number] NVARCHAR(200),
[Datey] datetime,
[ms] NVARCHAR(200),
[CH34] NVARCHAR(200),
[CH35] NVARCHAR(200),
[CH36] NVARCHAR(200),
[CH37] NVARCHAR(200),
[CH38] NVARCHAR(200),
[CH39] NVARCHAR(200),
[Alarm110] NVARCHAR(200),
[Alarm1120] NVARCHAR(200),
[Alarm2130] NVARCHAR(200),
[Alarm3140] NVARCHAR(200),
[AlarmOut] NVARCHAR(200)
)
Good luck !
P.S. One piece of the puzzle which is missing.... What data do you have in your dbo.sorting table ? This will dictate which fields end up in your temporary table, but you don't explain how this table is populated, or what data it contains.
The attributes
[BatchID] [nvarchar](50) NULL,
[CH31] [nvarchar](20) NULL,
[CH32] [nvarchar](20) NULL,
[CH33] [nvarchar](20) NULL
are missing from your file. With BULK_INSERT the columns have to match perfectly. Fix the number of columns, and it should fix the error.

How to execute SP in for each and union all results?

I have a table with certain records, let's call this the Priority table. For each record in this table I need to execute a stored procedure called GetProductsBasedOnPriorityRecord which returns records from a Product table.
All these results need to be returned as one UNION without duplicates.
I'm able to write the following C# pseodo code, but I have no idea on how to do this in SQL:
//DECLARE resultVariable
var products = new List<Product>();
//SELECT * FROM Priority and FOREACH over this
foreach(var prio in Priority) {
//EXEC GetProductsBasedOnPriorityRecord and UNION this on the resultVariable
products.Union(GetProductsBasedOnPriorityRecord(prio));
}
//RETURN resultVariable
return products;
You should not be writing SQL code in loops if you need it to perform even relatively well. But this is what I would do in this case.
-- build some variables
declare #prio table (prio varchar(100) not null)
declare #singlePrio varchar(50)
declare #sqlcmd varchar(50)
-- assuming that the output of the stored procedure is just a table of INTs
declare #output table (outputID int not null)
-- build the list to loop over
insert into #prio (prio)
select * from [Priority]
while exists (select 1 from #prio)
begin
select #singlePrio = (select top 1 prio from #prio)
--
insert into #output exec GetProductsBasedOnPriorityRecord #singlePrio
--
delete from #prio where prio = #singlePrio
end
-- using distinct because you want a 'union' but didnt say 'union all'
select distinct outputID from #output
Well you should be able to do it with a cursor. It's not always the best way. I assume that you are forced to use the existing stored procedure.
Example tables
CREATE TABLE [dbo].[Products](
[ProductID] [int] IDENTITY(1,1) NOT NULL,
[ProductName] [nchar](10) NULL,
[PriorityID] [int] NULL)
CREATE TABLE [dbo].[Priority](
[PriorityID] [int] IDENTITY(1,1) NOT NULL,
[PriorityCode] [nchar](10) NULL)
(with PKs etc).
Sample stored procedure:
ALTER PROCEDURE [dbo].[GetProductsBasedOnPriorityRecord]
-- Add the parameters for the stored procedure here
#PriorityID int = 0
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT * FROM Products WHERE PriorityID = #PriorityID
END
Then something like this:
DECLARE #PriorityID INT
DECLARE #table TABLE (ProductID INT, ProductName NCHAR(10), PriorityID INT)
DECLARE cur CURSOR FOR SELECT PriorityID FROM Priority
OPEN cur
FETCH NEXT FROM cur INTO #PriorityID
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO #table EXEC GetProductsBasedOnPriorityRecord #PriorityID
FETCH NEXT FROM cur INTO #PriorityID
END
CLOSE cur
DEALLOCATE cur
SELECT DISTINCT * FROM #table
Of course this makes some assumptions about your tables. Also (of course) a synthetic example like this is actually showing a long-winded way of doing something very simple.
Try this one -
DECLARE #SQL NVARCHAR(MAX)
IF OBJECT_ID (N'tempdb.dbo.#temp') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp (outputID INT NOT NULL)
SELECT #SQL = (
SELECT CHAR(13) + '
INSERT INTO #temp(outputID)
EXEC dbo.GetProductsBasedOnPriorityRecord '''
+ prio + ''''
FROM dbo.[Priority]
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
PRINT #SQL
EXEC sys.sp_executesql #SQL
SELECT DISTINCT outputID
FROM #temp

Resources