Hoe om gestoorde prosedure-uitvoer direk na 'n lêer op 'n FTP te skryf sonder om plaaslike of tydelike lêers te gebruik?

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

Vra

Ek wil die resultate van 'n gestoorde prosedure kry en dit in 'n CSV-lêer op 'n FTP-ligging plaas.

Die vangs is egter dat ek nie 'n plaaslike / tydelike lêer kan skep wat ek dan kan FTP oor nie.

Die benadering wat ek gevolg het, was om 'n SSIS-pakket te gebruik om 'n tydelike lêer te skep en dan 'n FTP-taak binne die pak te hê om die lêer oor te FTP, maar ons DBA's laat nie toe dat tydelike lêers op enige bedieners geskep word nie.

in antwoord op Yaakov Ellis

Ek dink ons ​​sal die DBA's moet oortuig om my ten minste 'n aandeel op 'n bediener te laat gebruik wat hulle nie bedryf nie, of hulle moet vra hoe hulle dit sal doen.

in antwoord op Kev

Ek hou van die idee van die CLR-integrasie, maar ek dink nie ons DBA's weet eers wat dit is nie lol en hulle sou dit seker ook nie toelaat nie.Maar ek sal dit waarskynlik binne 'n Skriptaak ​​kan doen in 'n SSIS-pakket wat geskeduleer kan word.

Was dit nuttig?

Oplossing

Hierdie stap-vir-stap voorbeeld is vir ander wat dalk op hierdie vraag afkom.Hierdie voorbeeld gebruik Windows Server 2008 R2 bediener en SSIS 2008 R2.Al gebruik die voorbeeld SSIS 2008 R2, is die logika wat gebruik word van toepassing op SSIS 2005 ook.Te danke aan @Kev vir die FTPWebRequest kode.

Skep 'n SSIS-pakket (Stappe om 'n SSIS-pakket te skep).Ek het die pakket in die begin in die formaat JJJJMMDD_hhmm genoem, gevolg deur SO staan ​​vir Stack Overflow, gevolg deur die SO vraag id, en laastens 'n beskrywing.Ek sê nie dat jy jou pakkie so moet noem nie.Dit is vir my om dit later maklik terug te verwys.Let daarop dat ek ook twee Databronne het, naamlik Avontuur werke en Oefen DB.Ek sal gebruik Avontuur werke databron, wat verwys na AdventureWorks databasis afgelaai vanaf hierdie skakel.Verwys skermskoot #1 onderaan die antwoord.

In die AdventureWorks databasis, skep 'n gestoorde prosedure met die naam dbo.GetCurrency met behulp van die onderstaande gegewe skrif.

CREATE PROCEDURE [dbo].[GetCurrency]
AS
BEGIN
    SET NOCOUNT ON;
    SELECT 
    TOP 10      CurrencyCode
            ,   Name
            ,   ModifiedDate 
    FROM        Sales.Currency
    ORDER BY    CurrencyCode
END
GO

Regskliek op die pakket se Verbindingsbestuurder-afdeling en kies Nuwe verbinding vanaf databron.Op die Kies Databron dialoog, kies Avontuur werke en klik OK.Jy behoort nou die Adventure Works-databron onder die Connection Managers-afdeling te sien.Verwys skermskoot #2, #3 en #4.

Skep die volgende veranderlikes op die pakket.Verwys skermskoot #5.

  • ColumnDelimiter:Hierdie veranderlike is van die tipe String.Dit sal gebruik word om die kolomdata te skei wanneer dit na die lêer geskryf word.In hierdie voorbeeld sal ons komma (,) gebruik en die kode is geskryf om slegs vertoonbare karakters te hanteer.Vir nie-vertoonbare karakters soos tab ( ), sal jy dalk die kode wat in hierdie voorbeeld gebruik word dienooreenkomstig moet verander.

  • Lêernaam:Hierdie veranderlike is van die tipe String.Dit sal die naam van die lêer bevat.In hierdie voorbeeld het ek die lêer as Currencies.csv genoem omdat ek 'n lys van geldeenheidname gaan uitvoer.

  • FTPPwagwoord:Hierdie veranderlike is van die tipe String.Dit sal die wagwoord vir die FTP-webwerf bevat.Ideaal gesproke moet die pakket geïnkripteer word om sensitiewe inligting te versteek.

  • FTPremotePath:Hierdie veranderlike is van die tipe String.Dit sal die FTP-vouerpad bevat waarheen die lêer opgelaai moet word.Byvoorbeeld as die volledige FTP URI is ftp://myFTPSite.com/ssis/samples/uploads, dan sal die RemotePath /ssis/samples/uploads wees.

  • FTPServerName:Hierdie veranderlike is van die tipe String.Dit sal die wortel-URI van die FTP-werf bevat.Byvoorbeeld as die volledige FTP URI is ftp://myFTPSite.com/ssis/samples/uploads, dan sal die FTPServerName bevat ftp://myFTPSite.com.U kan FTPRemotePath met hierdie veranderlike kombineer en 'n enkele veranderlike hê.Dit hang af van jou voorkeur.

  • FTPUserName: Hierdie veranderlike is van die tipe String.Dit sal die gebruikersnaam bevat wat gebruik sal word om aan die FTP-webwerf te koppel.

  • Lys Van Geldeenhede:Hierdie veranderlike is van die tipe Object.Dit sal die resultaatstel van die gestoorde prosedure bevat en dit sal in die Skriptaak ​​deurgelus word.

  • ShowHeader:Hierdie veranderlike is van die tipe Boolean.Dit sal waardes waar/onwaar bevat.Waar dui aan dat die eerste ry in die lêer Kolomname sal bevat en Onwaar dui aan dat die eerste ry nie Kolomname sal bevat nie.

  • SQLGetData:Hierdie veranderlike is van die tipe String.Dit sal die gestoorde prosedure-uitvoeringsverklaring bevat.Hierdie voorbeeld gebruik die waarde EXEC dbo.GetCurrency

Op die pakkie Beheer vloei oortjie, plaas 'n Voer SQL-taak uit en noem dit as Kry data.Dubbelklik op die Voer SQL-taak uit om die Voer SQL Taak Editor uit.Op die Algemeen afdeling van die Voer SQL Taak Editor uit, stel die Resultaatstel aan Full result set, die Verbinding aan Adventure Works, die SQLSourceType aan Variable en die BronVeranderlike aan User::SQLGetData.Op die Resultaatstel-afdeling, klik Voeg by knoppie.Stel die resultaatnaam na 0, dui dit die indeks en die Veranderlike aan User::ListOfCurrencies.Die afvoer van die gestoorde prosedure sal na hierdie objekveranderlike gestoor word.Klik OK.Verwys skermskoot #6 en #7.

Op die pakkie Beheer vloei oortjie, plaas 'n Skriptaak ​​onder die Voer SQL-taak uit en noem dit as Stoor na FTP.Dubbelklik op die Skriptaak ​​om die Skriptaakredakteur.Op die Skrip-afdeling, klik die Edit Script… knoppie.Verwys skermskoot #8.Dit sal die Visual Studio Tools for Applications (VSTA)-redigeerder na vore bring.Vervang die kode binne die klas ScriptMain in die redigeerder met die kode hieronder gegee.Maak ook seker dat jy die gebruiksstellings by die naamruimtes voeg System.Data.OleDb, System.IO, System.Net, System.Text.Verwys skermskoot #9 wat die kodeveranderings uitlig.Maak die VSTA-redigeerder toe en klik OK om die Skriptaakredigeerder toe te maak.Skripkode neem die objekveranderlike ListOfCurrencies en stoor dit in 'n DataTable met behulp van OleDbDataAdapter omdat ons OleDb-verbinding gebruik.Die kode loop dan deur elke ry en as die veranderlike ShowHeader op waar gestel is, sal die kode die Kolomname in die eerste ry insluit wat na die lêer geskryf is.Die resultaat word in 'n stringbuilder-veranderlike gestoor.Nadat die stringbouer-veranderlike met al die data gevul is, skep die kode 'n FTPWebRequest-objek en koppel dit aan die FTP Uri deur die veranderlikes FTPServerName, FTPRemotePath en FileName te kombineer deur die geloofsbriewe wat in die veranderlikes FTPUserName en FTPPassword verskaf word.Dan word die volledige stringbouer veranderlike inhoud na die lêer geskryf.Die metode WriteRowData word geskep om deur kolomme te loop en die kolomname of data-inligting te verskaf gebaseer op die parameters wat geslaag is.

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

Sodra die take opgestel is, behoort die pakket se beheervloei te lyk soos in die skermkiekie #10.

Skermskoot #11 toon die afvoer van die gestoorde prosedure uitvoering verklaring EXEC dbo.GetCurrency.

Voer die pakket uit.Skermskoot #12 toon suksesvolle uitvoering van die pakket.

Gebruik die FireFTP byvoeging beskikbaar in FireFox blaaier, het ek by die FTP-webwerf aangemeld en geverifieer dat die lêer suksesvol na die FTP-webwerf opgelaai is.Verwys skermskoot #13.

Deur die inhoud te ondersoek deur die lêer in Notepad++ oop te maak, wys dit dat dit ooreenstem met die gestoorde prosedure-uitvoer.Verwys skermskoot #14.

Die voorbeeld het dus gedemonstreer hoe om resultate van databasis na 'n FTP-webwerf te skryf sonder om tydelike/plaaslike lêers te gebruik.

Hoop dit help iemand.

Skermkiekies:

#1:Solution_Explorer

Solution_Explorer

#2:New_Connection_From_Data_Source

New_Connection_From_Data_Source

#3:Kies_databron

Select_Data_Source

#4:Verbindingsbestuurders

Connection_Managers

#5:Veranderlikes

Variables

#6:Voer_SQL_Taak_Editor_General uit

Execute_SQL_Task_Editor_General

#7:Execute_SQL_Task_Editor_Result_Set

Execute_SQL_Task_Editor_Result_Set

#8:Skrip_Taak_Editor

Script_Task_Editor

#9:Skrip_taak_VSTA_kode

Script_Task_VSTA_Code

#10:Control_Flow_Tab

Control_Flow_Tab

#11:Query_Results

Query_Results

#12:Package_Execution_Suksesvol

Package_Execution_Successful

#13:Lêer_In_FTP

File_In_FTP

#14:Lêer_Inhoud

File_Contents

Ander wenke

As jy toegelaat word om CLR-integrasie-samestellings te implementeer, kan jy eintlik FTP gebruik sonder om 'n tydelike lêer te hoef te skryf:

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

Is daar enige plek 'n bediener wat jy kan gebruik waar jy 'n tydelike lêer kan skep?Indien wel, maak 'n webdiens wat 'n skikking terugstuur wat die inhoud van die lêer bevat.Bel die webdiens vanaf die rekenaar waar jy 'n tydelike lêer kan skep, gebruik die inhoud van die skikking om die tydelike lêer te bou en ftp dit oor.

As daar nêrens is nie enigsins waar jy 'n tydelike lêer kan skep, ek sien nie hoe jy enigiets per FTP sal kan stuur nie.

Probeer 'n CLR-gebergde prosedure gebruik.Jy kan dalk met iets vorendag kom, maar sonder om eers 'n tydelike lêer te skep, kan dit steeds moeilik wees.Kan jy 'n deel op 'n ander masjien opstel en daarna skryf, en dan ftp van daar af?

Skrip vanaf die FTP-bediener, en bel net die gestoorde proc.

Die vangs is egter dat ek nie 'n plaaslike/tydelike lêer kan skep waarmee ek dan kan FTP nie.

Hierdie beperking maak nie sin nie, probeer mooi met DBA praat en verduidelik dit aan hom/haar.Dit is heeltemal redelik vir enige Windows-proses of werk om tydelike lêer(s) op toepaslike plek te skep, d.w.s.%TEMP% gids.Eintlik skep SSIS runtime self dikwels tydelike lêers daar - so as DBA jou toelaat om SSIS te laat loop, hy is wat jou toelaat om tydelike lêers te skep :).

Solank as wat DBA verstaan ​​dat hierdie tydelike lêers nie probleme of bykomende werklading vir hom skep nie (verduidelik dat hy nie spesiale toestemmings moet stel, of dit rugsteun, ens.), moet hy instem om jou te laat skep.

Die enigste instandhoudingstaak vir DBA is om periodiek %TEMP%-gids skoon te maak ingeval jou SSIS-taak misluk en die lêer agterlaat.Maar hy moet dit in elk geval doen, aangesien baie ander prosesse dieselfde kan doen.'n Eenvoudige SQL Agent-werk sal dit doen.

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top