我需要将查询结果导出到csv文件并将该文件放在网络共享文件夹中。
以下是该问题的更多详细信息:SP必须动态导出和传输文件,如果出现问题则引发错误。调用者必须立即得到响应,即如果没有错误,他可以假设结果已成功传输到文件夹。因此,每N分钟运行一次的DTS / SSIS作业不是一种选择。我知道问题有点像我必须在应用程序级别这样做,但如果所有这些都可以通过T-SQL完成,我会非常高兴。
答案 0 :(得分:2)
在我看来,您不是在等待问题的答案中的SQL代码。您问题的主要方面是安全方面。如果没有 sysadmin 权限并且没有新的安全漏洞,您应该怎么做才能实现您的需求?这是你认为的真正问题。
我发现至少有3种方法可以解决您的问题。但首先简单解释为什么在基于扩展存储过程的所有解决方案中存在sysadmin特权。像xp_cmdshell
这样的扩展存储过程非常陈旧。它们至少存在于SQL Server 4.2之前,这是在第一个Windows NT(NT 3.1)下运行的第一个Microsoft SQL Server。在旧版本的SQL Server中,我没有执行此类过程的安全限制,但后来有人制定了此类限制。重要的是要了解所有允许在xp_cmdshell
和sp_OACreate
等SQL Server帐户下启动任何流程的通用过程具有 sysadmin 权限限制。只有具有明确使用区域和基于角色的权限的面向任务的过程才能在没有安全漏洞的情况下解决问题。所以这是我之前承诺的3种解决方式:
xp_cmdshell
或sp_OACreate
,并在技术上实现您的要求(将一些信息导出到CSV文件中)。关于 EXECUTE AS 子句(请参阅http://msdn.microsoft.com/en-us/library/ms188354.aspx),您可以配置创建的存储过程,使其在具有 sysadmin 权限的帐户下运行。您将此过程的执行委派给具有某个SQL角色的用户,从授权权限方面更灵活。xp_cmdshell
和sp_OACreate
。您还应该对创建的过程使用基于角色的权限。在所有实施方式中,您应准确定义用于访问文件系统的帐户的您将保留密码的位置。您有不同的选择,都有相应的优点和缺点。可以使用模拟来允许使用最终用户的帐户访问文件系统。最好的方法取决于您在环境中的情况。
答案 1 :(得分:1)
您可以构建一个SQL代理作业,并通过触发器或SP从系统SP中删除它。该作业可能会调用SSIS或批量转储scrits ...返回即时错误消息可能是一个问题,但
一般来说,这是非常不寻常的要求 - 你想要完成什么?
更新: 经过一番思考后 - 这是一个设计问题,我无法通过使用SQL Server SP来找到解决方案。
过去 - 这就是我所做的:
这并不容易,但这是导出数据的最有效方式,从数据库到文件,无需通过浏览器访问应用服务器和用户PC。
答案 2 :(得分:1)
您可以使用OLE自动化吗?这很丑陋,你可能会使用一些基于集合的字符串构建技术而不是光标,但这里就是......
Declare @Dir varchar(4000)
Set @Dir = 'c:\some\path\accessible\to\SQLServer'
If @Dir IS NULL
Begin
print 'dir is null.'
Return 1
End
declare
@FilePath as varchar(255),
@DataToWrite as varchar(8000)
If right(@DataDir,1) <> '\'
Set @DataDir = @DataDir + '\'
Set @FilePath = @DataDir + 'filename.csv'
DECLARE @RetCode int , @FileSystem int , @FileHandle int
EXECUTE @RetCode = sp_OACreate 'Scripting.FileSystemObject' , @FileSystem OUTPUT
IF (@@ERROR|@RetCode > 0 Or @FileSystem < 0)
begin
RAISERROR ('could not create FileSystemObject',16,1)
End
declare @FileExists int
Execute @RetCode = sp_OAMethod @FileSystem, 'FileExists', @FileExists OUTPUT, @FilePath
--print '@FileExists = ' + cast(@FileExists as varchar)
If @FileExists = 1
Begin
RAISERROR ('file does not exist',16,1)
/*return 1*/
End
--1 = for reading, 2 = for writing (will overwrite contents), 8 = for appending
EXECUTE @RetCode = sp_OAMethod @FileSystem , 'OpenTextFile' , @FileHandle OUTPUT , @FilePath, 8, 1
IF (@@ERROR|@RetCode > 0 Or @FileHandle < 0)
begin
RAISERROR ('could not create open text file',16,1)
End
DECLARE CSV CURSOR
READ_ONLY
FOR
Select Anything From MyDataTable
order by whatever
DECLARE @fld1 nvarchar(50)
,@fld2 nvarchar(50)
OPEN CSV
FETCH NEXT FROM CSV INTO @fld1, @fld2
WHILE (@@fetch_status <> -1)
BEGIN
IF (@@fetch_status <> -2)
BEGIN
Set @DataToWrite = @fld1 + ',' + @fld2 + char(13) + char(10)
EXECUTE @RetCode = sp_OAMethod @FileHandle , 'Write' , NULL , @DataToWrite
IF (@@ERROR|@RetCode > 0)
begin
RAISERROR ('could not write to file',16,1)
End
END
FETCH NEXT FROM OpenOrders INTO @fld1, @fld2
END
CLOSE CSV
DEALLOCATE CSV
EXECUTE @RetCode = sp_OAMethod @FileHandle , 'Close' , NULL
IF (@@ERROR|@RetCode > 0)
RAISERROR ('Could not close file',16,1)
EXEC sp_OADestroy @FileSystem
return 0
End
答案 3 :(得分:1)
一般来说,不,如果没有大量的工作和努力以及系统管理权,这种工作就无法完成。
SQL是一个数据库引擎,专注于数据库问题,因此非常糟糕的文件操作工具。解决方法包括:
安全似乎是你的风雨。总的来说,当SQL弹出操作系统时,它拥有启动SQL服务的NT帐户的所有权限;如果您想限制网络访问,请仔细配置该帐户(并且永远不要将其设为域管理员!)
可以将xp_cmdshell作为没有sysadmin权限的用户调用,并将这些调用配置为不具有与SQL Service NT帐户相同的访问权限。根据BOL(SQL 2005及以上版本):
xp_cmdshell代理帐户
当不是sysadmin固定服务器角色成员的用户调用它时,xp_cmdshell使用存储在名为## xp_cmdshell_proxy_account ##的凭据中的帐户名和密码连接到Windows。如果此代理凭据不存在,则xp_cmdshell将失败。
可以通过执行sp_xp_cmdshell_proxy_account来创建代理帐户凭据。作为参数,此存储过程采用Windows用户名和密码。例如,以下命令为Windows域用户SHIPPING \ KobeR创建具有Windows密码sdfh%dkc93vcMt0的代理凭据。
因此,您的用户使用任何用户权限(不 sysadmin!)登录并执行存储过程,该过程调用xp_cmdshell,这将“拾取”已配置的任何代理权限。再次,尴尬,但听起来它会做你想要它做的事情。 (可能的限制因素是您只获得一个代理帐户,因此必须满足所有可能的需求。)
老实说,听起来像我最好的解决方案是:
那么,什么会启动对存储过程的调用?