Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 如何在不使用本地或临时文件的情况下将存储过程输出直接写入FTP上的文件?_Sql Server_Sql Server 2005_Ssis_Ftp - Fatal编程技术网

Sql server 如何在不使用本地或临时文件的情况下将存储过程输出直接写入FTP上的文件?

Sql server 如何在不使用本地或临时文件的情况下将存储过程输出直接写入FTP上的文件?,sql-server,sql-server-2005,ssis,ftp,Sql Server,Sql Server 2005,Ssis,Ftp,我希望获得存储过程的结果,并将其放入FTP位置上的CSV文件中 但问题是,我无法创建一个本地/临时文件,然后通过FTP传输 我所采取的方法是使用SSIS包创建一个临时文件,然后在包中有一个FTP任务来通过FTP传输文件,但我们的DBA不允许在任何服务器上创建临时文件 我认为我们需要说服DBA让我使用至少一个服务器上的共享,他们不运行,或者询问他们将如何操作 我喜欢CLR集成的想法,但我认为我们的DBA甚至不知道这是什么lol,他们可能也不允许。但我可能能够在SSIS包中的脚本任务中完成这项任务,

我希望获得存储过程的结果,并将其放入FTP位置上的CSV文件中

但问题是,我无法创建一个本地/临时文件,然后通过FTP传输

我所采取的方法是使用SSIS包创建一个临时文件,然后在包中有一个FTP任务来通过FTP传输文件,但我们的DBA不允许在任何服务器上创建临时文件

我认为我们需要说服DBA让我使用至少一个服务器上的共享,他们不运行,或者询问他们将如何操作


我喜欢CLR集成的想法,但我认为我们的DBA甚至不知道这是什么lol,他们可能也不允许。但我可能能够在SSIS包中的脚本任务中完成这项任务,该包可以被调度。

尝试使用CLR存储过程。您可能会想出一些办法,但如果不先创建临时文件,可能仍然很困难。你能在另一台机器上设置一个共享并写入,然后从那里通过ftp传输吗?

有没有可以用来创建临时文件的服务器?如果是这样,则创建一个返回包含文件内容的数组的web服务。从可以创建临时文件的计算机调用web服务,使用数组的内容构建临时文件并通过ftp将其传送


如果没有任何地方可以创建临时文件,我看不出您将如何通过FTP发送任何内容。

如果允许您实现CLR集成程序集,您实际上可以使用FTP而不必编写临时文件:

public static void DoQueryAndUploadFile(string uri, string username, string password, string filename)
{
    FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(uri + "/" + filename);
    ftp.Method = WebRequestMethods.Ftp.UploadFile;
    ftp.Credentials = new System.Net.NetworkCredential(username, password);

    using(StreamWriter sw = new StreamWriter(ftp.GetRequestStream()))
    {
        // Do the query here then write to the ftp stream by iterating DataReader or other resultset, following code is just to demo concept:
        for (int i = 0; i < 100; i++)
        {
            sw.WriteLine("{0},row-{1},data-{2}", i, i, i);
        }
        sw.Flush();
    }
}
publicstaticvoiddoqueryanduploadfile(字符串uri、字符串用户名、字符串密码、字符串文件名)
{
FtpWebRequest ftp=(FtpWebRequest)FtpWebRequest.Create(uri+“/”+文件名);
ftp.Method=WebRequestMethods.ftp.UploadFile;
ftp.Credentials=新系统.Net.NetworkCredential(用户名、密码);
使用(StreamWriter sw=newstreamwriter(ftp.GetRequestStream()))
{
//在此处执行查询,然后通过迭代DataReader或其他resultset写入ftp流,以下代码仅用于演示此概念:
对于(int i=0;i<100;i++)
{
sw.WriteLine(“{0},行-{1},数据-{2}”,i,i,i);
}
sw.Flush();
}
}

从FTP服务器编写脚本,然后调用存储的进程

但问题是我无法创造 一个本地/临时文件,我可以通过FTP传送

这个限制没有任何意义,试着与DBA友好地交谈并向他/她解释。任何Windows进程或作业在适当位置(即%TEMP%文件夹)创建临时文件是完全合理的。实际上,SSIS运行时本身通常会在那里创建临时文件——因此,如果DBA允许您运行SSIS,他将允许您创建临时文件:)

只要DBA了解这些临时文件不会给他带来问题或额外的工作量(解释他不需要设置特殊权限,或备份权限等),他应该同意让您创建它们


DBA唯一的维护任务是定期清理%TEMP%目录,以防SSIS作业失败并留下文件。但他无论如何都应该这样做,因为许多其他流程可能也会这样做。一个简单的SQL代理作业就可以做到这一点。

这个分步示例适用于可能偶然发现这个问题的其他人。此示例使用Windows Server 2008 R2 Server和SSIS 2008 R2。尽管示例使用SSIS 2008 R2,但所使用的逻辑也适用于SSIS 2005。感谢
@Kev
获得FTPWebRequest代码

创建SSIS包()。我以YYYYMMDD_hhmm的格式对包进行了命名,开头是SO,后面是SO表示堆栈溢出,后面是SO问题id,最后是描述。我不是说你应该这样命名你的包裹。这是我以后可以很容易地引用的。注意,我还有两个数据源,即AdventureWorks和PracticeDB。我将使用AdventureWorks数据源,它指向AdventureWorks数据库,从下载。请参阅答案底部的屏幕截图#1

在AdventureWorks数据库中,使用下面给定的脚本创建一个名为dbo.GetCurrency的存储过程

CREATE PROCEDURE [dbo].[GetCurrency]
AS
BEGIN
    SET NOCOUNT ON;
    SELECT 
    TOP 10      CurrencyCode
            ,   Name
            ,   ModifiedDate 
    FROM        Sales.Currency
    ORDER BY    CurrencyCode
END
GO
在包的连接管理器部分,右键单击并选择New Connection From Data Source。在“选择数据源”对话框中,选择“Adventure Works”,然后单击“确定”。现在,您应该可以在连接管理器部分下看到AdventureWorks数据源。请参阅屏幕截图#2#3#4

在包上,创建以下变量。请参阅屏幕截图#5

  • ColumnDelimiter:此变量的类型为String。这将用于在将列数据写入文件时分隔列数据。在本例中,我们将使用逗号(,),代码编写为仅处理可显示字符。对于tab(\t)等不可显示的字符,您可能需要相应地更改本示例中使用的代码

  • 文件名:此变量的类型为字符串。它将包含文件名。在本例中,我将文件命名为currences.csv,因为我将导出货币名称列表

  • FTPPassword:此变量的类型为字符串。这将包含FTP网站的密码。理想情况下,应该对包进行加密以隐藏敏感信息

  • FTPRemotePath:此变量的类型为字符串。这将包含文件应上载到的FTP文件夹路径。例如,如果完整的FTP URI为,则远程路径为/ssis/samples/uploads

  • FTPServerName:此变量的类型为
    using System;
    using System.Data;
    using Microsoft.SqlServer.Dts.Runtime;
    using System.Windows.Forms;
    using System.Data.OleDb;
    using System.IO;
    using System.Net;
    using System.Text;
    
    namespace ST_7033c2fc30234dae8086558a88a897dd.csproj
    {
        [System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
        public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
        {
    
            #region VSTA generated code
            enum ScriptResults
            {
                Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
                Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
            };
            #endregion
    
            public void Main()
            {
                Variables varCollection = null;
    
                Dts.VariableDispenser.LockForRead("User::ColumnDelimiter");
                Dts.VariableDispenser.LockForRead("User::FileName");
                Dts.VariableDispenser.LockForRead("User::FTPPassword");
                Dts.VariableDispenser.LockForRead("User::FTPRemotePath");
                Dts.VariableDispenser.LockForRead("User::FTPServerName");
                Dts.VariableDispenser.LockForRead("User::FTPUserName");
                Dts.VariableDispenser.LockForRead("User::ListOfCurrencies");
                Dts.VariableDispenser.LockForRead("User::ShowHeader");
                Dts.VariableDispenser.GetVariables(ref varCollection);
    
                OleDbDataAdapter dataAdapter = new OleDbDataAdapter();
                DataTable currencies = new DataTable();
                dataAdapter.Fill(currencies, varCollection["User::ListOfCurrencies"].Value);
    
                bool showHeader = Convert.ToBoolean(varCollection["User::ShowHeader"].Value);
                int rowCounter = 0;
                string columnDelimiter = varCollection["User::ColumnDelimiter"].Value.ToString();
                StringBuilder sb = new StringBuilder();
                foreach (DataRow row in currencies.Rows)
                {
                    rowCounter++;
                    if (rowCounter == 1 && showHeader)
                    {
                        WriteRowData(currencies, row, columnDelimiter, true, ref sb);
                    }
    
                    WriteRowData(currencies, row, columnDelimiter, false, ref sb);
                }
    
                string ftpUri = string.Concat(varCollection["User::FTPServerName"].Value,
                                              varCollection["User::FTPRemotePath"].Value,
                                              varCollection["User::FileName"].Value);
    
                FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(ftpUri);
                ftp.Method = WebRequestMethods.Ftp.UploadFile;
                string ftpUserName = varCollection["User::FTPUserName"].Value.ToString();
                string ftpPassword = varCollection["User::FTPPassword"].Value.ToString();
                ftp.Credentials = new System.Net.NetworkCredential(ftpUserName, ftpPassword);
    
                using (StreamWriter sw = new StreamWriter(ftp.GetRequestStream()))
                {
                    sw.WriteLine(sb.ToString());
                    sw.Flush();
                }
    
                Dts.TaskResult = (int)ScriptResults.Success;
            }
    
            public void WriteRowData(DataTable currencies, DataRow row, string columnDelimiter, bool isHeader, ref StringBuilder sb)
            {
                int counter = 0;
                foreach (DataColumn column in currencies.Columns)
                {
                    counter++;
    
                    if (isHeader)
                    {
                        sb.Append(column.ColumnName);
                    }
                    else
                    {
                        sb.Append(row[column].ToString());
                    }
    
                    if (counter != currencies.Columns.Count)
                    {
                        sb.Append(columnDelimiter);
                    }
                }
                sb.Append(System.Environment.NewLine);
            }
        }
    }