Table variable not working in dynamic SQL - sql

My trigger is as below ,
Alter TRIGGER [dbo].[LogTable_InsertTrigger] on [dbo].[std_table] AFTER INSERT
as
DECLARE #ColName varchar(50), #QueryText nvarchar(max)
declare #inserted TABLE(
[CountryID] [int] NOT NULL,
[Country] [nvarchar](255) NOT NULL,
[RegionId] [int] NULL
)
insert into #inserted
select * from inserted
DECLARE objCursor CURSOR FAST_FORWARD FOR
select ColName from dbo.getColumnNames('std_table')
OPEN objCursor
FETCH NEXT FROM objCursor INTO #ColName
WHILE ##FETCH_STATUS = 0
BEGIN
set #QueryText= '
insert into dbo.LogTable
(StandardType,Attribute,Action,NEwValue,UserId,ModifiedDate)
select ''Country'','''+#ColName+''',''Insert'','+#ColName+',1,getdate()
from #inserted'
EXEC sp_executesql #QueryText
FETCH NEXT FROM objCursor INTO #ColName
END
CLOSE objCursor
DEALLOCATE objCursor
When I try to insert to table std_table in DA Layer I get the exception Must declare the table variable "#inserted".
I couldn't use the inserted table directly because I am writing a dynamic query, inside which magic tables wont work. So I am trying to dump the data in inserted table to a temp table and to access from that.
I tried with
select *
into #inserted
from inserted
This works, but since my application is accessed by many users over network this will cause data issues. So I can't use this.

Several things wrong here.
That is a table variable, not a user defined table type.
If #temp tables work, why do you think that will cause data issues for multiple users? Each user will get their own version of the #temp table.
If you know there are exactly three columns and you can hard-code the table variable declaration, why do you need to then generate the three sets of inserts dynamically? Aren't the column names CountryID,Country,RegionID?
If you really need to do this dynamically then it seems like you could do this an easier way without an explicit cursor - not that this is necessarily a bad thing or that it will perform any worse than the below, but the cursor is just much more verbose and ugly code:
ALTER TRIGGER [dbo].[LogTable_InsertTrigger]
ON [dbo].[std_table]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
SELECT * INTO #t FROM inserted;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'';
SELECT #sql = #sql + CHAR(13) + CHAR(10) + N'INSERT INTO dbo.LogTable
(StandardType,Attribute,Action,NewValue,UserId,ModifiedDate)
SELECT ''Country'','''+ColName+''',''Insert'','+ColName+',1,GETDATE()
FROM #t;'
FROM dbo.GetColumnNames('std_table');
EXEC sp_executesql #sql;
END
GO

Related

How do I insert values in an idenity column over a linkedServer [duplicate]

I want to use a stored procedure to copy a table from my test database to a linked server with the same ID's / Identity but I can't get it to work..
I've set the IDENTITY_INSERT to ON but it still complains about the ID column.
Here's my procedure:
CREATE PROCEDURE [dbo].[TEST2PROD_CopyUIDataSServer]
AS Begin
declare #sql nvarchar(max)
-- First truncate target table
set #sql = 'EXEC [LINKEDSERVER].tempdb.sys.sp_sqlexec' + char(39)+ 'TRUNCATE Table [ProductManager].dbo.[UIData]' + char(39)+ ';'
---- SET IDENTITY_INSERT ON
set #sql = #sql + 'EXEC [LINKEDSERVER].tempdb.sys.sp_sqlexec' + char(39)+ 'SET IDENTITY_INSERT [ProductManager].[dbo].[UIData] ON' + char(39)+ ';'
---- INSERT UIDATA records from DB1 into linked server DB2
set #sql = #sql + 'WITH TestData as (SELECT * from ProductManager.dbo.UIData UID)' + NCHAR(13)+ 'INSERT INTO [LINKEDSERVER].[ProductManager].[dbo].[UIData]' + NCHAR(13) + 'select * from TestData;'
print #sql
exec (#sql)
end
But when I execute the SP it gives me the following error:
The OLE DB provider "SQLNCLI10" for linked server .... could not INSERT INTO table "[LINKEDSERVER].[ProductManager].[dbo].[UIData]" because of column "Id". The user did not have permission to write to the column.
Linked server properties RPC and RPC out are set to true. I hope someboy can help me out here?
UPDATE: I decided to pull things apart, first I copy the data from the local server to the linked server in a TEMP_TABLE where I don't have to deal with IDENTITY issues.
Then I wrote a stored procedure on the linked / remote server, since I'm not using SELECT * but specify the column list. Chances are this will work from the local server in an SP too but I don't have the time or interest to check it out yet..
USE [ProductManager]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[TEST2PROD_CopyBaseTables]
AS BEGIN
DECLARE #DestTable VARCHAR(50)
DECLARE #DestPath VARCHAR(50)
DECLARE #SrceTable VARCHAR(255)
declare #sql nvarchar(max)
DECLARE #columnList varchar(max)
DECLARE #err int
Begin TRY
declare #comma_delimited_list varchar(4000)
--- FIRST TRY WITH ONE TABLE, EXTENDABLE...
set #comma_delimited_list = 'UIData'
declare #cursor cursor
set #cursor = cursor static for
select * from dbo.Split(#comma_delimited_list,',') a
declare #naam varchar(50)
open #cursor
while 1=1 begin
fetch next from #cursor into #DestTable
if ##fetch_status <> 0 break
--Create tablenames
SET #SrceTable = '[ProductManager].[dbo].TEMP_' + #DestTable
SET #DestPath = '[ProductManager].[dbo].'+ #DestTable
print #srceTable;
print #DestTable;
--Truncate target table
set #sql ='TRUNCATE TABLE '+ #DestPath + ';'
--Insert statement needs column names
set #columnList =''
SELECT #columnList = coalesce(#columnList + '[' + name + '],','') FROM sys.columns Where OBJECT_NAME(OBJECT_ID) = #DestTable
if RIGHT(RTRIM(#columnList),1) = ','
begin
SET #columnList = LEFT(#columnList, LEN(#columnList) - 1)
end
--Transfer data from source table 2 destination
set #sql = #sql + ' SET IDENTITY_INSERT ' + #DestPath + ' ON;' + ' INSERT INTO ' + #DestPath + '(' + #columnList + ') SELECT ' + #columnList + ' FROM ' + #SrceTable
print #sql;
exec (#sql)
end
-- not strictly necessary w/ cursor variables since the will go out of scope like a normal var
close #cursor
deallocate #cursor
End Try
Begin Catch
declare #ErrorMsg nvarchar(MAX);
select #ErrorMsg = ERROR_MESSAGE();
SELECT #err = ##error IF #err <> 0 Return #err
end Catch
END
IDENTITY_INSERT doesn't work with linked servers AFAIK, unless you execute dynamic SQL that includes the SET IDENTITY_INSERT in the batch or have some code (Stored Proc for instance) on the remote server which does that for you.
The IDENTITY_INSERT is per-session (see MSDN) and when you use the remote server this will probably be in a different session from your statement executed via [LINKEDSERVER].tempdb.sys.sp_sqlexec, which causes it to fail as you see it happening.
You can insert an identity value into a table with an identity column on a linked server with the "SWITCH TO" trick.
If you haven't used the "SWITCH TO" trick to add and remove identity on a column, it's very quick, even on large tables!
Conceptually you simply create a new SCHEMA exactly like the table you are wanting to INSERT to without the identity defined. Then switch the table to that SCHEMA and do your INSERT. Then switch back to the SCHEMA with the identity defined.
The sample below has been tested on a linked server in AZURE.
All the caveats of using "SWITCH TO" apply (indexes must be the same, drop and recreate foreign keys, etc)
To test, you can run the full script below on an Linked Azure SQL Server database. You'll need to do a find/replace with [LINKED_SERVER_NAME] and [DATABASE_NAME], replacing with your values. On a non-Azure DB you may need to add "ON PRIMARY" to the table creations.
--Let's setup the example by creating a table with an IDENTITY column on the Linked Server
EXEC('
CREATE TABLE [DATABASE_NAME].[dbo].[Example_Table](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nchar](10) NULL
)
'
) AT [LINKED_SERVER_NAME]
--INSERT some data into the table
INSERT INTO [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table] ([Name]) VALUES ('Travis')
INSERT INTO [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table] ([Name]) VALUES ('Mike')
-- Looks good
SELECT * FROM [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table]
GO
-- Create a TABLE with an identical schema, without the identity defined
EXEC('
CREATE TABLE [DATABASE_NAME].[dbo].[Example_Table_temp](
[ID] [int] NOT NULL,
[Name] [nchar](10) NULL
)
'
) AT [LINKED_SERVER_NAME]
--Now Use the "SWITCH TO" to move the data to the new table
EXEC('
ALTER TABLE [DATABASE_NAME].[dbo].[Example_Table] SWITCH TO [DATABASE_NAME].[dbo].[Example_Table_temp]
'
) AT [LINKED_SERVER_NAME]
--Drop the old table (It should now be empty, but you may want to verify that if you are unsure here)
EXEC('
DROP TABLE [DATABASE_NAME].[dbo].[Example_Table]
'
) AT [LINKED_SERVER_NAME]
--Rename the new table back to the old table name
-- NOTE the lack of database and owner identifiers in the new name
-- NOTE the use of double single qoutes (ESCAPED single quotes)
EXEC('USE [DATABASE_NAME];
EXEC sp_rename ''[DATABASE_NAME].[dbo].Example_Table_temp'',''Example_Table''
'
) AT [LINKED_SERVER_NAME]
-- Now do your IDENTITY INSERTs !!!!
INSERT INTO [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table] (ID,[Name]) VALUES (888,'Travis')
INSERT INTO [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table] (ID,[Name]) VALUES (999,'Mike')
--Verify they got put in
SELECT * FROM [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table]
--Now let's switch it back to our SCHEMA with an IDENTITY
EXEC('
CREATE TABLE [DATABASE_NAME].[dbo].[Example_Table_temp](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nchar](10) NULL
)
ALTER TABLE [DATABASE_NAME].[dbo].[Example_Table] SWITCH TO [DATABASE_NAME].[dbo].[Example_Table_temp]
DROP TABLE [DATABASE_NAME].[dbo].[Example_Table]
EXEC sp_rename ''[DATABASE_NAME].[dbo].Example_Table_temp'',''Example_Table''
'
) AT [LINKED_SERVER_NAME]
--Data is still there
SELECT * FROM [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table]
GO
-- And note you can no longer INSERT the IDENTITY
INSERT INTO [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table] (ID,[Name]) VALUES (45,'Travis')
GO
You need to execute dynamic query Example :
exec [LINKSERVERNAME].[DATABASENAME].[SCHEMANAME].sp_executesql N'Your Query'
If any column set identity the you need to set SET IDENTITY_INSERT TargetTable ON and need to specified the column name. Example:
SET IDENTITY_INSERT TargetTable ON;
INSERT INTO TargetTable(Col1, Col2, Col3)
SELECT Col1, Col2, Col3 FROM SourceTable;
SET IDENTITY_INSERT TargetTable OFF;

Set a cursor on a table inside a table variable

All,
Trying to set a cursor on a table value inside a table variable, but it does not work. can anyone comment on how I can fix this?
** the code below is called from another stored procedure which provides the value for the tablename variable **
ALTER PROCEDURE [dbo].[usrSetLTDNormDist]
-- Add the parameters for the stored procedure here
#TableName Sysname,
---...
DECLARE #SQLCommand1 NVARCHAR(MAX) = N'
Set #RecCursor1 = Cursor For
Select [Volume], [TRANSDATE] from #TableName'
EXECUTE dbo.sp_executesql #sqlCommand1
-- Open Cursor
Open #RecCursor1
Fetch Next From #RecCursor1
Into #Volume, #TransDate
---...
Add PRINT #SQLCommand1 between the DECLARE and EXECUTE statements to review what is actually being executed. Based on your code snippet, you will see
Set #RecCursor1 = Cursor For
Select [Volume], [TRANSDATE] from #TableName
...that is, the value you set in #TableName is not automagically added to the script. Here's the way I write these things:
DECLARE #SQLCommand1 NVARCHAR(MAX)
SET #SQLCommand1 = replace(N'
Set #RecCursor1 = Cursor For
Select [Volume], [TRANSDATE] from <#TableName>'
,'<#TableName>', #TableName)
PRINT #SQLCommand1
EXECUTE dbo.sp_executesql #sqlCommand1
I use the < > characters to make the replaced values stand out.
This script demonstrates the general technique:
create table T (ID int not null)
go
insert into T(ID) values (99)
go
declare #TableName sysname
declare #ID int
set #TableName = 'T'
declare #SQL nvarchar(max) = N'declare boris cursor for select ID from ' +
QUOTENAME(#TableName)
exec sp_executesql #SQL
open boris
fetch next from boris into #ID
while ##FETCH_STATUS = 0
begin
print #ID
fetch next from boris into #ID
end
close boris
deallocate boris
Producing this output:
(1 row(s) affected)
99
However, I will offer my usual caution - if you're in a situation where you want to operate against multiple tables in the same way, this is usually a sign of a broken data model. Usually there ought to be a single table with additional columns containing data that serves to differentiate the values.

Loop through Column Names in a table and do a set of operations - SQL Server 2008

Thank you for helping me out through my previous tides.. I am currently working on SQL Server 2008 for one of my project, a part of which needs to use 22 columns for a set of similar operations.
The column names only differ by the number, e.g.
C1_1,C1_2,c1_3
Is there any way to loop through the column names? I tried out the following code, but it throws out an error
DECLARE #i INT
SET #i=2
while (#i<=22)
begin
SELECT [DEF].[CONCATENATE], SUM(DEF.[C1_+#i+_PREV]) as
[C1_#i_prev]
INTO #TMP_C1_#i_CONCATENATE_PREV
FROM DEF
GROUP BY DEF.[CONCATENATE]
SELECT [ABC].[CONCATENATE], SUM(ABC.[C1_#i_CURR]) as
[c1_#i_curr]
INTO #TMP_C1_#i_CONCATENATE_CURR
FROM ABC
GROUP BY ABC.[CONCATENATE]
UPDATE #tmp_var_concatenate_c1_#i
SET [Amount] = #TMP_C1_#i_CONCATENATE_PREV.[C1_#i_PREV]
FROM #tmp_var_concatenate_c1_#i
INNER JOIN
#TMP_C1_#i_CONCATENATE_PREV ON
#tmp_var_concatenate_c1_#i.[CONCATENATE] = #TMP_C1_#i_CONCATENATE_PREV.
[CONCATENATE]
Please forgive my ignorance, if I am doing something idiotic.
Thanks
This is part of the code in which the code is burping.
alter table #tmp_var_concatenate_C1_'+cast(#i as varchar)+'
add [ColA] varchar(255),
[ColB] Varchar(255),
[ColC] Varchar(255),
[ColD] VARCHAR(50),
[ColE] MONEY,
[ColF] MONEY
Is it because of the #tables that I am using ?? but, ideally, it shouldnt be an issue whether am using a Temp table or a reg. one..
You can use dynamic sql:
DECLARE #SQL varchar(max), #i INT
SET #i=2
while (#i<=22)
begin
/* Then cover all calculations with this one: */
SET #SQL='SELECT [DEF].[CONCATENATE], SUM(DEF.[C1_'+cast(#i as varchar)+'_PREV]) as
[C1_'+cast(#i as varchar)+'_prev]
INTO #TMP_C1_'+cast(#i as varchar)+'_CONCATENATE_PREV
FROM DEF
GROUP BY DEF.[CONCATENATE]
/* and all your code with the same trick in #i to the END */
'
--PRINT (#SQL) -- print it before use to see the result script
EXEC (#SQL)
/* Than do your iterations etc. */
set #i+=1
end
And don't forget to substitute all ' inside #SQL with ''.
Also you need to do all manipulations with temp tables inside #SQL, if you want to do final update outside the dynamic sql, just make tables real and then delete them.
[UPDATE]
As far as you faced with problem of altering temp tables, I tried to reproduce this error, but nothing happens, everything works fine. Please use this code as an example.
declare #sql varchar(max),#i int
set #i=2
while #i<=22
begin
set #sql='
select ID,Code into #TMP_C1_'+cast(#i as varchar)+'_CONCATENATE_PREV from (select 0 as ID, ''a'' as Code) t1
alter table #TMP_C1_'+cast(#i as varchar)+'_CONCATENATE_PREV add [Col1] varchar(255), [Col2] Varchar(255), [Col3] Money
select * from #TMP_C1_'+cast(#i as varchar)+'_CONCATENATE_PREV'
--print (#sql)
exec (#sql)
set #i+=1
end
First, I create temp table with dynamic name. Second, add new columns. The last is successful verifying. Did you execute all creations/alters in the same #sql-batch? If no, this won't work, because this tables are available only inside this batch (that's why we used varchar(max) when declared). Please describe your actions in details, maybe there is a mistake somewhere.

How can I spot in what database is a stored procedure with name 'myStoredProcedure'?

There are bunch of databases to the SQL server I am connected.
How should I query the sysobjects in order to spot in what database a stored procedure with name 'myStoredProcedure' is located ?
The query should return the database name.
Thanks
I know you are not asking for this, but I'd really download RedGate's Sql Search add-in for SSMS and use that. It allows you to find any object (proc, table, view, column, etc) on any database easily.
And it's free!
I'd give this a try:
CREATE TABLE ##DatabaseList
(
DatabaseName varchar(50)
)
EXECUTE SP_MSForEachDB 'USE [?]; INSERT INTO ##DatabaseList SELECT DB_NAME() FROM [sys].[objects] WHERE name = "MyStoredProcedure" AND type_desc = "SQL_STORED_PROCEDURE"'
SELECT * FROM ##DatabaseList
DROP TABLE ##DatabaseList
That's using the undocumented/ unsupported system stored procedure SP_MSForEachDb and writing any hits to a global temp table, then outputting the contents to the Results window before dropping the table. If you just need to know which database (or databases - there may of course be more than one) has an appropriately named SP, this should do it. If you want to use the output elsewhere as a parameter, it may take a little more work.
By the way, I'm only learning this stuff myself over the last few months so if anyone can critique the above and suggest a better way to go at it I'm happy to receive feedback. Equally, I can answer any further questions posted here to the best of my ability.
Cheers
So out of curiosity I decided to try write this myself, especially since ADG mentioned his solution was using an unsupported, undocumented procedure. This could also be expanded to take a 2nd parameter so where it checks the type = P (stored Proc) you could probably change it to look for other things like views / tables etc.
My solution is a bit long but here goes:
CREATE PROCEDURE spFindProceduresInDatabases
(
#ProcedureName NVARCHAR(99)
)
AS
BEGIN
-- Get all the database names and put them into a table
DECLARE #Db TABLE (DatabaseName Varchar(99))
INSERT INTO #Db SELECT name FROM Sys.databases
-- Declare a table to hold our results
DECLARE #results TABLE (DatabaseName VARCHAR(99))
-- Make a Loop
-- Declare a variable to be incremented
DECLARE #count INT
SET #count = 0
-- Declare the end condition
DECLARE #endCount INT
SELECT #endCount = COUNT(*) FROM #Db
-- Loop through the databases
WHILE (#count < #endCount )
BEGIN
-- Get the database we are going to look into
DECLARE #dbWeAreChecking VARCHAR(99)
SELECT TOP 1 #dbWeAreChecking = DatabaseName FROM #Db
DELETE FROM #Db WHERE DatabaseName = #dbWeAreChecking
-- Create and execute our query
DECLARE #Query NVARCHAR(3000)
SET #Query = N'SELECT #outParam = COUNT(*) FROM '+#dbWeAreChecking+'.sys.sysobjects WHERE type = ''P'' and name = #ProcedureName'
Declare #outParam INT
print (#Query)
DECLARE #ParmDefinition NVARCHAR(500)
DECLARE #IntVariable INT
SET #ParmDefinition = N'#ProcedureName VARCHAR(99),#outParam INT OUTPUT'
SET #IntVariable = 35
EXECUTE sp_executesql
#Query ,
#ParmDefinition,
#ProcedureName,
#outParam = #outParam OUTPUT
-- If we have a result insert it into the results table
If (#outParam > 0)
BEGIN
INSERT INTO #results(DatabaseName) VALUES(#dbWeAreChecking)
END
-- Increment the counter
SET #count = (#count + 1)
END
-- SELECT ALL OF THE THINGS!!!
SELECT * FROM #results
END

How to BULK INSERT a file into a *temporary* table where the filename is a variable?

I have some code like this that I use to do a BULK INSERT of a data file into a table, where the data file and table name are variables:
DECLARE #sql AS NVARCHAR(1000)
SET #sql = 'BULK INSERT ' + #tableName + ' FROM ''' + #filename + ''' WITH (CODEPAGE=''ACP'', FIELDTERMINATOR=''|'')'
EXEC (#sql)
The works fine for standard tables, but now I need to do the same sort of thing to load data into a temporary table (for example, #MyTable). But when I try this, I get the error:
Invalid Object Name: #MyTable
I think the problem is due to the fact that the BULK INSERT statement is constructed on the fly and then executed using EXEC, and that #MyTable is not accessible in the context of the EXEC call.
The reason that I need to construct the BULK INSERT statement like this is that I need to insert the filename into the statement, and this seems to be the only way to do that. So, it seems that I can either have a variable filename, or use a temporary table, but not both.
Is there another way of achieving this - perhaps by using OPENROWSET(BULK...)?
UPDATE:
OK, so what I'm hearing is that BULK INSERT & temporary tables are not going to work for me. Thanks for the suggestions, but moving more of my code into the dynamic SQL part is not practical in my case.
Having tried OPENROWSET(BULK...), it seems that that suffers from the same problem, i.e. it cannot deal with a variable filename, and I'd need to construct the SQL statement dynamically as before (and thus not be able to access the temp table).
So, that leaves me with only one option which is to use a non-temp table and achieve process isolation in a different way (by ensuring that only one process can be using the tables at any one time - I can think of several ways to do that).
It's annoying. It would have been much more convenient to do it the way I originally intended. Just one of those things that should be trivial, but ends up eating a whole day of your time...
You could always construct the #temp table in dynamic SQL. For example, right now I guess you have been trying:
CREATE TABLE #tmp(a INT, b INT, c INT);
DECLARE #sql NVARCHAR(1000);
SET #sql = N'BULK INSERT #tmp ...' + #variables;
EXEC master.sys.sp_executesql #sql;
SELECT * FROM #tmp;
This makes it tougher to maintain (readability) but gets by the scoping issue:
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'CREATE TABLE #tmp(a INT, b INT, c INT);
BULK INSERT #tmp ...' + #variables + ';
SELECT * FROM #tmp;';
EXEC master.sys.sp_executesql #sql;
EDIT 2011-01-12
In light of how my almost 2-year old answer was suddenly deemed incomplete and unacceptable, by someone whose answer was also incomplete, how about:
CREATE TABLE #outer(a INT, b INT, c INT);
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'SET NOCOUNT ON;
CREATE TABLE #inner(a INT, b INT, c INT);
BULK INSERT #inner ...' + #variables + ';
SELECT * FROM #inner;';
INSERT #outer EXEC master.sys.sp_executesql #sql;
It is possible to do everything you want. Aaron's answer was not quite complete.
His approach is correct, up to creating the temporary table in the inner query. Then, you need to insert the results into a table in the outer query.
The following code snippet grabs the first line of a file and inserts it into the table #Lines:
declare #fieldsep char(1) = ',';
declare #recordsep char(1) = char(10);
declare #Lines table (
line varchar(8000)
);
declare #sql varchar(8000) = '
create table #tmp (
line varchar(8000)
);
bulk insert #tmp
from '''+#filename+'''
with (FirstRow = 1, FieldTerminator = '''+#fieldsep+''', RowTerminator = '''+#recordsep+''');
select * from #tmp';
insert into #Lines
exec(#sql);
select * from #lines
Sorry to dig up an old question but in case someone stumbles onto this thread and wants a quicker solution.
Bulk inserting a unknown width file with \n row terminators into a temp table that is created outside of the EXEC statement.
DECLARE #SQL VARCHAR(8000)
IF OBJECT_ID('TempDB..#BulkInsert') IS NOT NULL
BEGIN
DROP TABLE #BulkInsert
END
CREATE TABLE #BulkInsert
(
Line VARCHAR(MAX)
)
SET #SQL = 'BULK INSERT #BulkInser FROM ''##FILEPATH##'' WITH (ROWTERMINATOR = ''\n'')'
EXEC (#SQL)
SELECT * FROM #BulkInsert
Further support that dynamic SQL within an EXEC statement has access to temp tables outside of the EXEC statement. http://sqlfiddle.com/#!3/d41d8/19343
DECLARE #SQL VARCHAR(8000)
IF OBJECT_ID('TempDB..#BulkInsert') IS NOT NULL
BEGIN
DROP TABLE #BulkInsert
END
CREATE TABLE #BulkInsert
(
Line VARCHAR(MAX)
)
INSERT INTO #BulkInsert
(
Line
)
SELECT 1
UNION SELECT 2
UNION SELECT 3
SET #SQL = 'SELECT * FROM #BulkInsert'
EXEC (#SQL)
Further support, written for MSSQL2000 http://technet.microsoft.com/en-us/library/aa175921(v=sql.80).aspx
Example at the bottom of the link
DECLARE #cmd VARCHAR(1000), #ExecError INT
CREATE TABLE #ErrFile (ExecError INT)
SET #cmd = 'EXEC GetTableCount ' +
'''pubs.dbo.authors''' +
'INSERT #ErrFile VALUES(##ERROR)'
EXEC(#cmd)
SET #ExecError = (SELECT * FROM #ErrFile)
SELECT #ExecError AS '##ERROR'
http://msdn.microsoft.com/en-us/library/ms191503.aspx
i would advice to create table with unique name before bulk inserting.