I have an SQL script which I want to run on multiple databases. The script runs a couple of update and insert statements and I also want to open and parse an xml file on different paths.
The issue I have is that I know where the file I want to open is (the directory) but I don't know its name (the name is random) but the extension is always .profile (which is a xml file) and there is only one file in each directory.
I wonder how I can open a XML/profile file without knowing its exact name using MS SQL.
As far as I understand your question correctly:
declare #files table (ID int IDENTITY, fileName varchar(max))
insert into #files execute xp_cmdshell 'dir <yourdirectoryhere>\*.profile /b'
declare #fileName varchar(max)
select top 1 #fineName = fileName * from #files
does what you want but is based on calling xp_cmdshell and it's usually a very bad idea to use it.
Try something along the lines of this:
DECLARE #output NVARCHAR(MAX)
CREATE TABLE #OUTPUT
(
OUTPUT VARCHAR(255) NULL
)
INSERT #OUTPUT
EXEC #output = XP_CMDSHELL
'DIR "C:\temp\*.profile" /B '
SELECT *
FROM #OUTPUT
DROP TABLE #OUTPUT
As explained here (and that's just one way), you can access disk contents from SQL Server, provided your permissions are working fine.
IIRC, the following options need to be enabled. However, you need them anyway to access files from SQL Server.
EXEC sp_configure 'show advanced options', 1
GO
RECONFIGURE
GO
EXEC sp_configure 'xp_cmdshell', 1
GO
Related
I'm trying to create a folder in the file explorer from within SQL Server Management Studio 18. Is this even possible? I know with VBA you can do it. I tried some code I found online, I even enabled xp_cmdshell and it runs but no folder is created. I tried with this code but pretty sure I'm missing something.
declare #cmdpath nvarchar(60)
set #cmdpath = 'MD '+ #Location
exec master.dbo.xp_cmdshell #cmdpath
or this one:
declare #FilePath varchar(100)
set #FilePath = 'D:\FolderTest'
EXEC master.dbo.xp_create_subdir #FilePath
SQL is a means of relating to a database. Typically queries are embedded in another file (a python script or java application for example). The job of creating files and folders falls outside the database and would not be handled by a query.
So the short answer is no. SQL is not the thing to use to make files and folders.
To the wonderful people at Stack who have helped me time and time again... I am trying to run a bulk insert routine for all the files in a folder. This is my approach, but I seem to have hit a roadblock with a message saying "Access is denied in my select statement"
EXEC [dbo].[procReadFolder] 'C:\Users\ABC\Downloads\NYSE_2015'
I have admin access to all the folders and files so unsure of the next step.
See Logic below:
ALTER procedure [dbo].[procReadFolder] #path sysname
as
begin
set nocount on
declare #dirContent table(
id int identity(1,1),
FileName sysname NULL
)
declare #cmd nvarchar(512)
set #cmd = 'DIR /b ' + #path
insert into #dirContent
exec master..xp_cmdshell #cmd
select * from #dirContent
-- Code to Loop through all the records in the file
-- To be written
-- Routine that takes the file name as a parameter and inserts the file
EXEC [dbo].[BulkInsert] 'Path'
end
Result Set:
1 Access is denied.
2 NULL
You will need to ensure that the account that the SQL Server Service is running as has access to the specific path.
The stored procedure is executed under the security context of the account configured to run the SQL Server Service, and therefore that is the account that will need to be given permissions to the folder on the drive.
I changed the SQL service account to another user account "SQLService" instead of the default NT/MSSQLServer account and it worked
I am running SQL Server 2005 on Windows Server 2003 machine.
I have a requirement to accumulate small text files into a bigger one.
So I use
exec xp_cmdshell #sql
where #sql=
'copy /b'+#sourcePath+#sourceFile+' '+#destinationPath+#NewFileName
Both the source and destination paths are on a separate server.
Seldom this process fails and I don't find anything else in the event or SQL Server logs.
The Surface Area Config for xp_cmdshell is also enabled.
Please help.....
I just tested this on my sql server 2005 and EXEC dbo.xp_cmdshell always returns output (even in the case of a bogus command) in the form of a table. For C#, if you call this code with ExecuteNonQuery, then call it with ExecuteReader and read the output. Alternatively, you could dump the output in a table so that you can look at it later at your leisure. Create a table like this :
CREATE TABLE [dbo].[xp_cmdShellOutput](
[errorMsg] [nvarchar](max) NULL
)
and then use this code :
DECLARE #sql AS VARCHAR(600)
SELECT #sql = '<your command>'
INSERT dbo.xp_cmdShellOutput(errorMsg)
EXEC dbo.xp_cmdshell #sql
I've been searching for a solution on how to get the filename of using SQL Server. I know that it's possible if you're using C#. But how is it done in SQL?
For example, I have a file (example: uploadfile.txt) located in C:\ that is about to be uploaded. I have a table which has a field "filename". How do I get the filename of this file?
This is the script that I have as of the moment.
-- Insert to table
BULK INSERT Price_Template_Host
FROM 'C:\uploadfile.txt'
WITH
(
FIELDTERMINATOR = '\t',
ROWTERMINATOR = '\n'
)
-- Insert into transaction log table filename and datetime()
To the best of my knowledge, there is no direct method in T-SQL to locate a file on the file system. After all this is not what the language is intended to be used for. From the script you have provided, BULK INSERT requires that the fully qualified file name already be known at the time of the statement call.
There are of course a whole variety of ways you could identify/locate a file, outside of using T-SQL for example using SSIS, perhaps you could use xp_cmdshell (has security caveats), or create a managed code module within SQL Server to perform this task.
To provide you with specific guidence, it may help if you could provide us all with details of the business process that you are trying to implement.
I would personally attach this problem with an SSIs package, which would give you much more flexibility in terms of load and subsequent logging. However, if you're set on doing this through T-SQL, consider exec'ing dynamically-constructed SQL:
declare #cmd nvarchar(max), #filename nvarchar(255)
set #filename = 'C:\uploadfile.txt'
set #cmd =
'BULK INSERT Price_Template_Host
FROM '''+#filename+'''
WITH
(
FIELDTERMINATOR = ''\t'',
ROWTERMINATOR = ''\n''
)'
-- Debug only
print #cmd
-- Insert to table
exec(#cmd)
-- Insert into transaction log table filename and datetime()
insert into dbo.LoadLog (filename, TheTime)
values (#filename, getdate())
If I understand your question correctly, this paramaterizes the filename so that you can capture it further down in the script.
How can I read the value of a system environment variable in a T-SQL script?
This is to run on SQL Server 2005.
To "read the value of a system environment variable in a T-SQL script" you can set SQL Management Studio to use "sqlcmd Mode".
Then you can use like this:
Print '$(TEMP)'
:r $(Temp)\Member.sql
go
I'm not sure how this is done outside of "SQL Management Studio" but it should be hard to find out.
This should give you a list (provided you allow people to execute xp_cmdshell)
exec master..xp_cmdshell 'set'
Note: xp_cmdshell is a security hazard ...
You could also do this with a managed stored proc an extended stored proc or via a com component.
Hey, if you want to get the server name, just call SELECT ##SERVERNAME
xp_cmdshell is generally best avoided for security reasons.
You're better off using a CLR assembly. Here's a good introduction to creating a CLR assembly.
You can use System.Environment.GetEnvironmentVariable() in C# - you'll find more info on how to do that here.
Thanks for the answers.
They helped me get to a working solution, although this is probably not the most advanced method:
declare #val varchar(50)
create table #tbl (h varchar(50))
insert into #tbl exec master..xp_cmdshell 'echo %computername%'
set #val = (select top 1 h from #tbl)
drop table #tbl
Specifically I was trying to get the hostname, the echo %computername% could be replaced with the hostname system command. But this now works for any environment variable.
To determine a specific environment variable in T-SQL (MS SQL Server) you can do something like:
Grant Security Permissions
use [master]
execute sp_configure 'show advanced options', 1
reconfigure
go
execute sp_configure 'xp_cmdshell', 1
reconfigure
go
grant execute on xp_cmdshell to [DOMAIN\UserName]
grant control server to [DOMAIN\UserName]
go
Source: https://stackoverflow.com/a/13605864/601990
Use Environment Variables
-- name of the variable
declare #variableName nvarchar(50) = N'ASPNETCORE_ENVIRONMENT'
-- declare variables to store the result
declare #environment nvarchar(50)
declare #table table (value nvarchar(50))
-- get the environment variables by executing a command on the command shell
declare #command nvarchar(60) = N'echo %' + #variableName + N'%';
insert into #table exec master..xp_cmdshell #command;
set #environment = (select top 1 value from #table);
-- do something with the result
if #environment = N'Development' OR #environment = N'Staging'
begin
select N'test code'
end
else
begin
select N'prod code'
end
Also remember to restart the SQL Server Service when changing the Environment Variables.