كيفية كتابة الإجراء المخزن الإخراج مباشرة إلى ملف على ملقم FTP دون استخدام المحلية أو temp الملفات ؟

StackOverflow https://stackoverflow.com/questions/20587

سؤال

أريد الحصول على نتائج الإجراء المخزن ووضعها في ملف CSV على FTP الموقع.

الصيد هو على الرغم من أنني لا يمكن إنشاء محلي/ملف مؤقت أستطيع أن ثم FTP أكثر.

نهج كنت مع استخدام حزمة SSIS إلى إنشاء ملف مؤقت ومن ثم يكون بروتوكول نقل الملفات المهمة داخل حزمة بروتوكول نقل الملفات ملف جديد ولكن لدينا DBA لا تسمح ملفات مؤقتة يتم إنشاؤها على أي من الخوادم.

في الرد على يعقوب إليس

أعتقد أننا سوف تحتاج إلى إقناع DBA إلى اسمحوا لي أن استخدام على الأقل مشاركة على ملقم أنها لا تعمل, أو نطلب منهم كيف أنها سوف تفعل ذلك.

في رد على "كيف"

أنا أحب فكرة CLR التكامل ، ولكن لا أعتقد أن لدينا DBA حتى أعرف ما هو لول وأنها لن تسمح بذلك أيضا.ولكن أنا سوف ربما تكون قادرة على القيام بذلك في إطار مهمة البرنامج نصي في حزمة SSIS التي يمكن أن تكون في الموعد المقرر.

هل كانت مفيدة؟

المحلول

هذا خطوة بخطوة مثال للآخرين الذين قد تتعثر على هذا السؤال.يستخدم هذا المثال Windows Server 2008 R2 و SSIS 2008 R2.على الرغم من ذلك ، على سبيل المثال يستخدم SSIS 2008 R2, يستخدم المنطق ينطبق على SSIS 2005 وكذلك.شكرا @Kev عن FTPWebRequest التعليمات البرمجية.

إنشاء حزمة SSIS (خطوات إنشاء حزمة SSIS).لقد سمى حزمة في شكل YYYYMMDD_hhmm في البداية تليها لذلك تقف على تجاوز سعة المكدس ، تليها لذا السؤال id, و أخيرا وصف.أنا لا أقول أن عليك أن اسم الحزمة الخاصة بك مثل هذا.هذا هو الرجوع بسهولة هذا مرة أخرى في وقت لاحق.علما أن لدي أيضا اثنين من مصادر البيانات وهي مغامرة يعمل و الممارسة DB.وسوف تستخدم مغامرة يعمل مصدر البيانات الذي يشير إلى 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

على حزمة اتصال مدير قسم انقر بزر الماوس الأيمن فوق وحدد اتصال جديد من مصدر البيانات.على حدد مصدر البيانات مربع الحوار حدد مغامرة يعمل ثم انقر فوق طيب.يجب أن تشاهد الآن Works مصدر البيانات تحت اتصال مديري القسم.تشير الصورة #2, #3 و #4.

على حزمة إنشاء المتغيرات التالية.تشير الصورة #5.

  • ColumnDelimiter:هذا المتغير من نوع String.هذا وسوف تستخدم لفصل عمود البيانات عندما يتم كتابة إلى الملف.في هذا المثال سنقوم باستخدام فاصلة ( ، ) كتابة التعليمات البرمجية في التعامل معها فقط للعرض الشخصيات.غير القابلة للعرض شخصيات مثل علامة التبويب (t), قد تحتاج إلى تغيير التعليمات البرمجية المستخدمة في هذا المثال وفقا لذلك.

  • اسم الملف:هذا المتغير من نوع String.سوف يحتوي على اسم الملف.في هذا المثال, يجب تسمية الملف باسم العملات.csv لأن أنا ذاهب إلى تصدير قائمة من أسماء العملات.

  • FTPPassword:هذا المتغير من نوع String.هذا سوف تحتوي على كلمة المرور إلى موقع FTP.من الناحية المثالية, يجب أن تكون الحزمة المشفرة لإخفاء المعلومات الحساسة.

  • FTPRemotePath:هذا المتغير من نوع String.هذا سوف تحتوي على FTP مجلد المسار إلى الملف الذي يجب أن يتم تحميلها.على سبيل المثال إذا كان بروتوكول نقل الملفات كاملة URI هو ftp://myFTPSite.com/ssis/samples/uploads, ثم RemotePath سيكون /ssis/عينة/التحميلات.

  • FTPServerName:هذا المتغير من نوع String.هذا سوف تحتوي على FTP الموقع الجذر URI.على سبيل المثال إذا كان بروتوكول نقل الملفات كاملة URI هو ftp://myFTPSite.com/ssis/samples/uploads, ثم FTPServerName سوف تحتوي على ftp://myFTPSite.com.يمكنك الجمع بين FTPRemotePath مع هذا المتغير ويكون متغير واحد.فمن يصل إلى تفضيل الخاص بك.

  • FTPUserName:هذا المتغير من نوع String.هذا سوف تحتوي على اسم المستخدم الذي سيتم استخدامه الاتصال إلى موقع FTP.

  • ListOfCurrencies:هذا المتغير من نوع الكائن.هذا سوف تحتوي على مجموعة من الإجراء المخزن و سيكون يحلق في مهمة البرنامج النصي.

  • ShowHeader:هذا متغير من النوع Boolean.هذا سوف تحتوي على قيم true/false.صحيح يشير إلى أن الصف الأول في ملف يحتوي على أسماء الأعمدة و كاذبة تشير إلى أن الصف الأول لن يحتوي على أسماء الأعمدة.

  • SQLGetData:هذا المتغير من نوع String.هذا سوف تحتوي على الإجراء المخزن تنفيذ البيان.يستخدم هذا المثال قيمة EXEC dbo.GetCurrency

على الحزمة التحكم في التدفق علامة التبويب مكان تنفيذ المهام SQL وتسميته كما الحصول على البيانات.انقر نقرا مزدوجا على تنفيذ المهام SQL لجلب تنفيذ المهام SQL محرر.على العامة القسم تنفيذ المهام SQL محرر, تعيين ResultSet إلى Full result set, ، اتصال إلى Adventure Works, ، SQLSourceType إلى Variable و SourceVariable إلى User::SQLGetData.على نتيجة مجموعة القسم ، انقر فوق الزر إضافة.تعيين النتيجة الاسم 0, هذا يدل على مؤشر متغير User::ListOfCurrencies.إخراج الإجراء المخزن سيتم حفظ هذا الكائن المتغير.انقر طيب.تشير الصورة #6 و #7.

على الحزمة التحكم في التدفق علامة التبويب مكان مهمة البرنامج نصي دون تنفيذ المهام SQL وتسميته كما حفظ FTP.انقر نقرا مزدوجا فوق البرنامج النصي مهمة لجلب المهمة Script Editor.على سيناريو القسم, انقر على Edit Script… زر.تشير الصورة #8.هذا وسوف طرح أدوات Visual Studio for Applications (VSTA) محرر.استبدال التعليمات البرمجية داخل الطبقة ScriptMain في محرر التعليمات البرمجية أدناه.أيضا, تأكد من أن قمت بإضافة باستخدام بيانات مساحات System.Data.OleDb, System.IO, System.Net, System.Text.تشير الصورة #9 الذي يسلط الضوء على التغييرات في التعليمات البرمجية.إغلاق VSTA محرر انقر فوق موافق لإغلاق المهمة Script Editor.رمز البرنامج النصي يأخذ متغير الكائن ListOfCurrencies ويخزنها في DataTable مع مساعدة من OleDbDataAdapter لأننا باستخدام OleDb الصدد.رمز ثم حلقات عبر كل صف و إذا كان المتغير ShowHeader تعيين إلى true ، رمز سوف تشمل أسماء الأعمدة في الصف الأول كتابة إلى الملف.يتم تخزين النتيجة في بـ stringbuilder متغير.بعد سلسلة باني متغير يتم تعبئة جميع البيانات المدونة يخلق FTPWebRequest موضوع يتصل FTP Uri من خلال الجمع بين المتغيرات FTPServerName, FTPRemotePath واسم الملف باستخدام وثائق التفويض المقدمة في المتغيرات FTPUserName و FTPPassword.ثم سلسلة كاملة باني محتويات المتغير تتم كتابة إلى الملف.طريقة WriteRowData يتم إنشاء حلقة من خلال الأعمدة وتقديم أسماء الأعمدة البيانات أو المعلومات استنادا إلى المعلمات التي تم تمريرها.

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);
        }
    }
}

مرة واحدة المهام تم تكوين حزمة التحكم في التدفق يجب أن تبدو كما هو مبين في الصورة #10.

لقطة #11 يظهر الإخراج من الإجراء المخزن تنفيذ بيان EXEC dbo.GetCurrency.

تنفيذ الحزمة.لقطة #12 يظهر نجاح تنفيذ الحزمة.

باستخدام FireFTP الإضافة متوفرة في فايرفوكس متصفح, لقد دخلت إلى موقع FTP و التحقق من أن الملف قد تم بنجاح تحميلها إلى موقع FTP.الرجوع لقطة #13.

فحص محتويات طريق فتح الملف في المفكرة++ يظهر أنه يتطابق مع تخزين الناتج الداخلي.الرجوع لقطة #14.

وهكذا ، على سبيل المثال أظهرت كيفية كتابة النتائج من قاعدة بيانات FTP الموقع دون الحاجة إلى استخدام مؤقت/الملفات المحلية.

على أمل أن يساعد شخص ما.

لقطات:

#1:Solution_Explorer

Solution_Explorer

#2:New_Connection_From_Data_Source

New_Connection_From_Data_Source

#3:Select_Data_Source

Select_Data_Source

#4:Connection_Managers

Connection_Managers

#5:المتغيرات

Variables

#6:Execute_SQL_Task_Editor_General

Execute_SQL_Task_Editor_General

#7:Execute_SQL_Task_Editor_Result_Set

Execute_SQL_Task_Editor_Result_Set

#8:Script_Task_Editor

Script_Task_Editor

#9:Script_Task_VSTA_Code

Script_Task_VSTA_Code

#10:Control_Flow_Tab

Control_Flow_Tab

#11:Query_Results

Query_Results

#12:Package_Execution_Successful

Package_Execution_Successful

#13:File_In_FTP

File_In_FTP

#14:File_Contents

File_Contents

نصائح أخرى

إذا سمح لك لتنفيذ CLR التكامل جمعيات هل يمكن فعلا استخدام بروتوكول نقل الملفات دون الحاجة إلى كتابة الملف المؤقت:

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();
    }
}

هل هناك خادم في أي مكان يمكنك استخدامها حيث يمكنك إنشاء ملف مؤقت?إذا كان الأمر كذلك, جعل خدمة ويب بإرجاع صفيف يحتوي على محتويات الملف.استدعاء خدمة ويب من جهاز الكمبيوتر حيث يمكنك إنشاء ملف مؤقت ، استخدام محتويات المصفوفة لبناء ملف temp و ftp أكثر من ذلك.

إذا لم يكن هناك حيث في كل حيث يمكنك إنشاء ملف مؤقت, أنا لا أرى كيف كنت سوف تكون قادرة على إرسال أي شيء عن طريق بروتوكول نقل الملفات.

حاول استخدام CLR الإجراء المخزن.كنت قد تكون قادرة على الخروج مع شيء ما ، ولكن دون إنشاء ملف مؤقت ، فقد يكون من الصعب.يمكن أن تقوم بإعداد مشاركة على جهاز آخر و كتابة ذلك ، ثم ftp من هناك ؟

السيناريو من ملقم FTP فقط الاتصال المخزنة proc.

الصيد هو على الرغم من أنني لا يمكن إنشاء محلي/ملف مؤقت أستطيع أن ثم FTP أكثر.

هذا القيد لا يجعل من أي معنى ، حاول التحدث إلى DBA بشكل جيد و شرح له/لها.فمن المعقول تماما عن أي عملية أو وظيفة لإنشاء ملف مؤقت(s) في المكان المناسب ، أي%TEMP% مجلد.في الواقع, SSIS وقت التشغيل نفسها في كثير من الأحيان بإنشاء ملفات مؤقتة هناك - حتى إذا DBA يسمح لك لتشغيل SSIS انه هو مما يسمح لك لإنشاء ملفات مؤقتة :).

طالما DBA يدرك أن هذه الملفات المؤقتة لا تخلق مشكلة أو عبء عمل إضافي له (شرح أنه لا لا يجب تعيين أذونات خاصة ، أو العودة عنها ، إلخ) ، فإنه يجب أن توافق على السماح إنشائها.

الصيانة فقط مهمة DBA هو دوري تنظيف %TEMP% الدليل في حالة SSIS فشل مهمة ويترك الملف وراء.ولكن كان يجب عليك القيام بذلك على أي حال, العديد من العمليات الأخرى قد تفعل الشيء نفسه.بسيطة عميل SQL العمل سوف تفعل هذا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top