BULK INSERT - Access Denied - sql

I am struggling with this error for some time. I have the command below:
-- Declare main variables
DECLARE #command VARCHAR(500);
DECLARE #currentPath VARCHAR(100);
SELECT #currentPath = '\\SERVERNAME.Domain\Temp\';
DECLARE #currentFile VARCHAR(100);
DECLARE #currentDate VARCHAR(100) = REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 126),'-',''),'T','T'),':','');
-- BILL OF MATERIALS
SET #currentFile = 'File'
TRUNCATE TABLE SampleData.iTable;
SET DATEFORMAT dmy;
SET #command = ' BULK INSERT SampleData.iTable'
SET #command = #command + ' FROM ''' + #currentPath + #currentFile + '.csv'''
SET #command = #command + ' WITH '
SET #command = #command + ' (FIRSTROW = 2, '
SET #command = #command + ' FIELDTERMINATOR = '';'', '
SET #command = #command + ' ROWTERMINATOR = ''\n'', '
SET #command = #command + ' MAXERRORS = 99999, '
SET #command = #command + ' ERRORFILE = ''' + #currentPath + #currentFile + '_ERROR_' + #currentDate + '.csv'','
SET #command = #command + ' TABLOCK '
SET #command = #command + ' ) '
EXECUTE (#command)
It works well if I run it from Management Studio inside the SQL Server VM. If I run this bulk insert from management studio from my computer or any other computer, connected to the same SQL Server instance, with the same user, same database and everything.. I get error below:
Cannot bulk load because the file "\SERVERNAME.Domain\Temp\File.csv" could not be opened. Operating system error code 5(Access is denied.).
Possible reason is that user is in a different domain than the SQL Server and shared path.. but not confident this is the issue as well because I can successfully run the BULK INSERT from the SQL Server VM
Another possible reason is active directory delegation, but I don't have permission to check this and also why would it be delegation if I can run the command from the SQL VM server?
Any bit of advice is appreciated!
Thanks
Felipe Carlesso

Related

Backup script I've been using with no issues for a while tossing an error on new database

I've been using the code below to drop and create a new backup named (current year database)_daily at midnight to allow my team to test new scripts or updates to our student information system.
It worked all last year, and this year for reasons I can't figure out, the script is tossing an error.
Here is the script:
USE master;
GO
-- the original database (use 'SET #DB = NULL' to disable backup)
DECLARE #SourceDatabaseName varchar(200)
DECLARE #SourceDatabaseLogicalName varchar(200)
DECLARE #SourceDatabaseLogicalNameForLog varchar(200)
DECLARE #query varchar(2000)
DECLARE #DataFile varchar(2000)
DECLARE #LogFile varchar(2000)
DECLARE #BackupFile varchar(2000)
DECLARE #TargetDatabaseName varchar(200)
DECLARE #TargetDatbaseFolder varchar(2000)
-- ****************************************************************
SET #SourceDatabaseName = '[DST18000RD]' -- Name of the source database
SET #SourceDatabaseLogicalName = 'DST18000RD' -- Logical name of the DB ( check DB properties / Files tab )
SET #SourceDatabaseLogicalNameForLog = 'DST18000RD_log' -- Logical name of the DB ( check DB properties / Files tab )
SET #BackupFile = 'F:\Dev_Databases\Temp\backup.dat' -- FileName of the backup file
SET #TargetDatabaseName = 'DST18000RD_Daily' -- Name of the target database
SET #TargetDatbaseFolder = 'F:\Dev_Databases\Temp\'
-- ****************************************************************
SET #DataFile = #TargetDatbaseFolder + #TargetDatabaseName + '.mdf';
SET #LogFile = #TargetDatbaseFolder + #TargetDatabaseName + '.ldf';
-- Disconnect any users using #TargetDatabaseName
USE [master];
DECLARE #kill varchar(8000) = '';
SELECT #kill = #kill + 'kill ' + CONVERT(varchar(5), session_id) + ';'
FROM sys.dm_exec_sessions
WHERE database_id = db_id('DST18000RD_Daily')
EXEC(#kill);
-- Backup the #SourceDatabase to #BackupFile location
IF #SourceDatabaseName IS NOT NULL
BEGIN
SET #query = 'BACKUP DATABASE ' + #SourceDatabaseName + ' TO DISK = ' + QUOTENAME(#BackupFile,'''')
PRINT 'Executing query : ' + #query;
EXEC (#query)
END
PRINT 'OK!';
-- Drop #TargetDatabaseName if exists
IF EXISTS(SELECT * FROM sysdatabases WHERE name = #TargetDatabaseName)
BEGIN
SET #query = 'DROP DATABASE ' + #TargetDatabaseName
PRINT 'Executing query : ' + #query;
EXEC (#query)
END
PRINT 'OK!'
-- Restore database from #BackupFile into #DataFile and #LogFile
SET #query = 'RESTORE DATABASE ' + #TargetDatabaseName + ' FROM DISK = ' + QUOTENAME(#BackupFile,'''')
SET #query = #query + ' WITH MOVE ' + QUOTENAME(#SourceDatabaseLogicalName,'''') + ' TO ' + QUOTENAME(#DataFile ,'''')
SET #query = #query + ' , MOVE ' + QUOTENAME(#SourceDatabaseLogicalNameForLog,'''') + ' TO ' + QUOTENAME(#LogFile,'''')
PRINT 'Executing query : ' + #query
EXEC (#query)
PRINT 'OK!'
The script is not mine, I put together two scripts to get me what I needed. Our old database DST17000RD, this script still works flawlessly. On the new database DST18000RD, I get this error:
Executing query : BACKUP DATABASE [DST18000RD] TO DISK = 'F:\Dev_Databases\Temp\backup.dat'
Processed 1209552 pages for database 'DST18000RD', file 'DST18000RD' on file 23.
Processed 2 pages for database 'DST18000RD', file 'DST18000RD_log' on file 23.
BACKUP DATABASE successfully processed 1209554 pages in 139.942 seconds (67.525 MB/sec).
OK!
OK!
Executing query : RESTORE DATABASE DST18000RD_Daily FROM DISK = 'F:\Dev_Databases\Temp\backup.dat' WITH MOVE 'DST18000RD' TO 'F:\Dev_Databases\Temp\DST18000RD_Daily.mdf' , MOVE 'DST18000RD_log' TO 'F:\Dev_Databases\Temp\DST18000RD_Daily.ldf'
Msg 3234, Level 16, State 2, Line 3
Logical file 'DST18000RD' is not part of database 'DST18000RD_Daily'. Use RESTORE FILELISTONLY to list the logical file names.
Msg 3013, Level 16, State 1, Line 3
RESTORE DATABASE is terminating abnormally.
OK!
Some things to note that may just be me barking up the wrong tree. DST17000RD database is compatibility level SQL Server 2012 (110) and the DST18000RD database is SQL Server 2017 (140). The server was upgraded and migrated a couple months ago before the new database was created.
Any help is appreciated. From what I can tell, I feel like the script is not renaming the MDF and LDF files before it tries to copy them for the *_daily database? Honestly I'm not sure. I'm a pretend DBA, self taught on an as needed basis. Thank you in advance for your help!
The error is telling you got the logical name of the db file wrong:
SET #SourceDatabaseLogicalName = 'DST18000RD' -- Logical name of the DB ( check DB properties / Files tab )
and to run:
RESTORE FILELIST ONLY FROM DISK = 'F:\Dev_Databases\Temp\backup.dat'
To see the correct logical file names.
The issue is you are trying to change the file logical name during the database restore, which is not possible even if you use the MOVE clause.
The MOVE clause allows you to change the location and the names of the physical files but does not do anything for the logical names.
Fix
You will have to use the existing logical names for your database, but once you have restored the database then use ALTER DATABASE command to change the logical names of your files using the following command:
USE [master];
GO
ALTER DATABASE [DST18000RD]
MODIFY FILE ( NAME = DST17000RD , NEWNAME = DST18000RD );
GO

SQL Server - rename column within stored procedure with different databases

I have searched and searched and cannot work out how to resolve my problem. I am actually not sure it is possible but thought I'd post here and check.
The issue:
I have a stored procedure where I make the following call (there are 2 because I was trying different things but both fail):
SET #olddate = '1606'
SET #newdate = '1706'
SET #TableName = 'sometablename'
SET #sql = 'SP_RENAME ''[DBName' + #olddate + '.dbo.' + #TableName + #olddate +'].[ColumnName' + #olddate + 'restofname]'',''[ColumnName' + #newdate + 'restofname]'''
EXECUTE sp_executesql #sql
Other option:
SET #olddate = '1606'
SET #newdate = '1706'
SET #TableName = 'sometablename'
SET #old = '[DBName' + #olddate + '.dbo.' + #TableName + #olddate+']."[ColumnName' + #olddate + 'restofname]"'
SET #new = 'ColumnName' + #newdate + 'restofname'
EXECUTE sp_rename #objname = #old,#newname = #new, #objtype = 'COLUMN'
I saved this in a stored procedure, and then ran it in another query which has a different database context and got the following error for the first:
No item by the name of '[DBName.dbo.TableName.ColumnName]' could be found in the current database '[Other database]', given that #itemtype was input as '(null)'.
and this for the second:
Either the parameter #objname is ambiguous or the claimed #objtype (COLUMN) is wrong.
Now, what I'm wondering is: can I even do this? write a stored procedure that runs sp_rename in a table in one database and then call that stored procedure from another database?
I've also tried every permutation of putting open and closed brackets, [ and ] around parts of my old and new column names. Also tried putting N before the string. It's a bit of trial and error though and thus far nothing has worked.
You cannot put your DBName and schemaName and tablename into one bracket [ ] You need to enclose each with a bracket. And dont use brackets around you new name since it will take these brackets into the name. Its a string so you can just put spaces and what you like into your name.
declare #TableName nvarchar(max)
declare #ColumName nvarchar(max)
declare #NewColumn nvarchar(max)
declare #sql nvarchar(max)
SET #NewColumn = 'newtest'
SET #ColumName = 'test'
SET #TableName = 'trassor'
SET #sql = 'SP_RENAME ''[YOURDBNAME].[YOURSCHEMANAME].['+ #TableName +'].['+#ColumName+']'', '''+#NewColumn+''', ''COLUMN'''
/* SET #sql = 'SP_RENAME ''[LegogSpass].[dbo].['+ #TableName +'].['+#ColumName+']'', '''+#NewColumn+''', ''COLUMN''' */
PRINT #SQL
EXECUTE sp_executesql #sql
First of all use a select #sql query before the sp_executesql statement to view how the dynamic statement has been formed.
This gives you an understanding of the error.
In your case the brackets have been placed in a wrong way.
Either remove them or add individually to dbname,schemaname,tablename and column.
Also, you were missing the 'column' at the end of the sp_rename statement.
declare #sql nvarchar(max),#olddate varchar(10),#newdate varchar(10),#TableName varchar(100)
SET #olddate = '1606'
SET #newdate = '1706'
SET #TableName = 'sometablename'
SET #sql = 'SP_RENAME ''DBName' + #olddate + '.dbo.' + #TableName + #olddate +'.ColumnName' + #olddate + 'restofname'',''ColumnName' + #newdate + 'restofname'',''Column'''
select #sql
EXECUTE sp_executesql #sql
Thanks for all the help. I actually figured out the issue subsequently. I know the brackets were wrong but that wasn't the issue (as I tried all sorts of different combinations of brackets and none of them worked).
set #old = #TableName +'.[ColumnName' + #olddate + 'restofname]'
set #new = 'ColumnName' + #newdate + 'restofname'
execute ('use DBName exec sp_rename ''' + #old + ''', ''' + #new + ''', ''COLUMN''')
The trick was to include "Use Database" within the execute statement.

Writing file to network drive in stored proc

I have a stored proc that can write a file to a network drive using BCP, by creating a temporary drive on the database server that maps to the shared drive on another server. It is working correctly, however, I am returning an error from the last EXEC command, which says There are open files and/or incomplete directory searches pending on the connection to U:. I am guessing that it is trying to execute the delete drive command before it has finished writing the file. If I run the statement after running the proc, it will successfully delete the drive. Here is the proc:
CREATE PROCEDURE dn_ExportFile
#ServerName varchar(50),
#ServerPath varchar(500),
#FileName varchar(100),
#Query varchar(max),
#UserName varchar(100),
#Password varchar(100),
#Drive varchar(1) = 'U'
AS
BEGIN
SET NOCOUNT ON;
DECLARE #cmd VARCHAR(8000)
--Set up virtual drive pointing to desired path
SET #cmd = 'NET USE ' + #Drive + ': ' + #ServerPath + ' /user:' + #ServerName + '\' + #UserName + ' ' + #Password
PRINT #cmd
EXEC xp_cmdshell #cmd
--Export data using BCP to virtual drive
SET #cmd = 'BCP "' + #Query + '" QUERYOUT "' + #Drive + ':\' + #FileName + '" -c -t -T'
PRINT #cmd
EXEC xp_cmdshell #cmd
--Delete virtual drive
SET #cmd = 'NET USE ' + #Drive + ': /delete'
PRINT #cmd
EXEC xp_cmdshell #cmd
END
Is there a way to successfully delete the temporary drive within the stored procedure?
I suspect it can't happen while the calling proc is still in scope. So you might try a wrapper stored procedure that does:
EXEC dbo.dn_ExportFile ...;
SET #cmd = 'NET USE ' + #Drive + ': /delete';
PRINT #cmd;
EXEC xp_cmdshell #cmd;
Otherwise I still think you're doing this in the wrong place. Have the program that calls this procedure call the command and dictate the path.

Is there a way to include go in dymanic SQL?

DECLARE #SQL VARCHAR(100)
DECLARE #dbName VARCHAR(100)--
SET #dbName = 'somedbname'--
SET #sql = 'USE [' + #dbName + ']' + CHAR(13) + CHAR(10)
SET #sql = #sql + 'GO' + CHAR(13) + CHAR(10)-- Print the command
EXEC (#sql)
When I run this it gives error Incorrect syntax near 'GO' has someone found workaround to this?
Requirement : I need to include stored procedure creation in switched database.
GO is not a SQL statement - it is a command recognized by the SQL Server utilities (e.g. sqlcmd, osql, SQL Server Management Studio code editor).
However, you can change the database without the GO command.

SQL script how to add a tab or new line within script

I have a SQL script that acquires table names and creates trigger for those tables. When I open the trigger after creating it all of the code is on one line. How would I go about adding tab and new line characters within the script to make the trigger more readable.
Example code:
SET #SQL = 'ALTER TRIGGER [dbo].[TRG_' + SUBSTRING(#TABLE_NAME,5, LEN(#TABLE_NAME)) + '_$AUD] '
SET #SQL = #SQL + 'ON [dbo].[' + #TABLE_NAME + '] '
SET #SQL = #SQL + 'FOR UPDATE, DELETE '
SET #SQL = #SQL + 'AS '
SET #SQL = #SQL + 'DECLARE '
SET #SQL = #SQL + '#BIT INT, '
SET #SQL = #SQL + '#FIELD INT, '
SET #SQL = #SQL + '#CHAR INT '
For MS SQL at least, you can either use CHAR() with the correct ASCII values and concatenate at the correct places in your strings, or you can just include the newlines, tabs, etc. within your SQL strings themselves. The string can span multiple lines. For example, this should work:
SET #SQL = 'ALTER TRIGGER [dbo].[TRG_' + SUBSTRING(#TABLE_NAME,5, LEN(#TABLE_NAME)) + '_$AUD]
ON [dbo].[' + #TABLE_NAME + ']
...
'
This won't change the actual trigger definition, but you could use a tool like Instant SQL Formatter, when you need to work on it.
use this
SET #SQL = 'ALTER TRIGGER [dbo].[TRG_' + SUBSTRING(#TABLE_NAME,5, LEN(#TABLE_NAME)) + '_$AUD]
ON [dbo].[' + #TABLE_NAME + ']
FOR UPDATE, DELETE
AS
DECLARE
#BIT INT,
#FIELD INT,
#CHAR INT '