2

下面给出的 SSIS 脚本任务接受一个股票代码和您想要返回的日期范围,并返回一个 CSV 格式的下载,可用于提取价格历史记录,但它不起作用,我不知道为什么。关于这个 SSIS 深思熟虑的概念的完整信息可以在下面的链接中找到。

SSIS / ETL 示例 – 雅虎股票和共同基金价格历史

您可以从以下链接下载示例 SSIS 包。

SkyDrive 上的示例包

以下 SSIS 脚本任务没有错误,但没有下载文件:

我刚开始理解这段代码,似乎这个链接被细分为像这里这样的组件,并且它必须使用正确的值,但我不明白为什么它没有检索文件。

ichart.finance.yahoo.com/table.csv?s={symbol}&a={startMM}&b={startDD}&c=
{‌​startYYYY}&d={endMM}&e={endDD}&f={endYYYY}&g={res}&ignore=.csv

我正在使用的脚本任​​务代码:

using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using System.Configuration;
using System.Collections.Generic;
using System.Data.Sql;
using System.Data.SqlClient;
using System.Net;
using System.Collections.Specialized;
using System.Linq;

using Hash = System.Collections.Generic.Dictionary<string, string>;

namespace ST_361aad0e48354b30b8152952caab8b2b.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

        static string dir;
        static DateTime end;
        const string CSV_FORMAT = "Id,Cusip,Date,Open,High,Low,Close,Volume,Adj Close";

        public void Main()
        {
            // end date is today minus one day (end of day)
            end = DateTime.Now;

            // output directory stored in SSIS variable
            // which can be set at runtime
            dir = System.IO.Path.Combine(Dts.Variables["OutputCSV"].Value.ToString(), end.ToString("yyyyMMdd"));
            if (!System.IO.Directory.Exists(dir))
                System.IO.Directory.CreateDirectory(dir);

            // connection string to our database
            var connectionString = Dts.Variables["ConnectionString"].Value.ToString();

            // the sql command to execute
            var sql = Dts.Variables["PriceHistorySqlCommand"].Value.ToString();

            var list = new List<Hash>();
            using (var cnn = new SqlConnection(connectionString))
            {
                cnn.Open();
                using (var cmd = new SqlCommand(sql, cnn))
                {
                    cmd.CommandTimeout = 0;
                    var dr = cmd.ExecuteReader();
                    while (dr.Read())
                    {
                        // store result in temporary hash
                        var h = new Hash();
                        h["cusip"] = dr["cusip"].ToString();
                        h["symbol"] = dr["symbol"].ToString();
                        h["product_id"] = dr["product_id"].ToString();
                        h["last_price_dt_id"] = dr["last_price_dt_id"].ToString();

                        list.Add(h);

                        // process batches of 100 at a time 
                        // (This requires System.Threading.dll (CTP of parallel extensions) to be installed in the GAC)
                        if (list.Count >= 100)
                        {
                            System.Threading.Tasks.Parallel.ForEach(list, item =>
                            {
                                var dt = item["last_price_dt_id"].TryGetDateFromDateDimensionId(end.AddYears(-100));
                                DownloadPriceHistory(item["product_id"], item["cusip"], item["symbol"], dt);
                            });
                            list.Clear();
                        }
                    }
                }
            }


            // TODO: Add your code here
            Dts.TaskResult = (int)ScriptResults.Success;
        }

        static void DownloadPriceHistory(string id, string cusip, string symbol, DateTime begin)
        {
            // get write path
            var path = System.IO.Path.Combine(dir, cusip + ".csv");
            var url = String.Format("http://ichart.finance.yahoo.com/table.csv?s={0}&d={1}&e={2}&f={3}&g=d&a={4}&b={5}&c={6}&ignore=.csv",
                symbol.ToUpper(),
                (end.Month - 1).ToString("00"), end.Day.ToString("00"), end.Year,
                (begin.Month - 1).ToString("00"), begin.Day.ToString("00"), begin.Year);
            string csv;

            using (WebClient web = new WebClient())
            {
                try
                {
                    var text = web.DownloadString(url);
                    var lines = text.Split('\n');
                    System.Text.StringBuilder sb = new System.Text.StringBuilder();
                    int i = 0;
                    foreach (var line in lines)
                    {
                        // skip first line its a header
                        if (i == 0)
                            sb.AppendLine(CSV_FORMAT);
                        // ensure line being added is not null
                        else if (false == String.IsNullOrEmpty(line) && false == String.IsNullOrEmpty(line.Trim()))
                            sb.AppendLine(id + "," + cusip + "," + line);
                        i++;
                    }
                    // add header and body
                    csv = sb.ToString();
                }
                catch (System.Net.WebException)
                {
                    // 404 error
                    csv = CSV_FORMAT;
                }
            }

            System.IO.File.WriteAllText(path, csv);
        }
    }

    /// <summary>
    /// Some simple extension methods.
    /// </summary>
    public static class ExtensionMethods
    {
        /// <summary>
        /// Gets a datetime object from a dimension id string for example '20090130' would be translated to
        /// a proper datetime of '01-30-2009 00:00:00'. If the string is empty than we default to the passed
        /// in <paramref name="defaultIfNull"/>.
        /// </summary>
        /// <param name="str">The string</param>
        /// <param name="defaultIfNull">The default null.</param>
        /// <returns>Returns the datetime.</returns>
        public static DateTime TryGetDateFromDateDimensionId(this string str, DateTime defaultIfNull)
        {
            if (String.IsNullOrEmpty(str)) return defaultIfNull;
            return DateTime.Parse(str.Substring(4, 2) + "/" + str.Substring(6, 2) + "/" + str.Substring(0, 4));
        }
    }
}
4

1 回答 1

15

使用 SSIS 从 Yahoo Finance Chart 网站导入股票价格历史记录:

还有另一种方法可以使用 SSIS 将股票代码价格历史从 Yahoo Chart 网站导入数据库。SSIS 2008 R2这是一个使用with database in编写的示例包SQL Server 2008 R2

SO_14797886.dtsx使用Business Intelligence Development Studio (BIDS)并创建一个OLE DB连接到您的数据库的连接管理器/数据源,创建一个名为(比如说)的 SSIS 包。此示例使用OLEDB_Sora.ds连接到Sora运行实例的本地计算机上的数据库的数据源KIWI\SQLSERVER2008R2KIWI是机器名,SQLSERVER2008R2是实例名。

在数据库中执行以下给定脚本以创建两个表。

  • 表格dbo.TickerSymbols将包含有关代码列表的信息以及您希望导入价格文件的开始和结束日期以及导入的解决方案。分辨率可以包含类似dfor 的值dayw对于weekly; m对于monthly; 并且y对于yearly.

  • 表格dbo.TickerPriceHistory将保存从雅虎财经图表网站下载的品种的价格历史信息。

  • 插入脚本为股票代码AAPL( Apple) 添加了四条记录;MSFT( Microsoft); GOOG( Google); 和YHOO( Yahoo)。每条记录都设置了不同的日期范围和分辨率。

创建表格并插入一些股票代码数据的脚本:

CREATE TABLE dbo.TickerSymbols
(
        Id int IDENTITY(1,1) NOT NULL
    ,   Symbol varchar(10) NOT NULL
    ,   StartDate datetime NOT NULL
    ,   EndDate datetime NOT NULL
    ,   Resolution char(1) NOT NULL
    ,   CONSTRAINT [PK_TickerSymbols] PRIMARY KEY CLUSTERED ([Id] ASC)
);
GO

CREATE TABLE dbo.TickerPriceHistory
(
        Id int IDENTITY(1,1) NOT NULL
    ,   Symbol varchar(10) NOT NULL
    ,   PriceDate datetime NOT NULL
    ,   PriceOpen numeric(18,2) NULL
    ,   PriceHigh numeric(18,2) NULL
    ,   PriceLow numeric(18,2) NULL
    ,   PriceClose numeric(18,2) NULL
    ,   Volume bigint NULL
    ,   AdjustmentClose numeric(18,2) NULL
    ,   CONSTRAINT [PK_TickerPriceHistory] PRIMARY KEY CLUSTERED ([Id] ASC)
);
GO

INSERT INTO dbo.TickerSymbols (Symbol, StartDate, EndDate, Resolution) VALUES
        ('AAPL', '2012-02-01', '2012-02-04', 'd')
    ,   ('GOOG', '2013-01-01', '2013-01-31', 'w')
    ,   ('MSFT', '2012-09-01', '2012-11-30', 'm')
    ,   ('YHOO', '2012-01-01', '2012-12-31', 'y')
    ;
GO

在 SSIS 包上,创建以下变量。

  • EndDate:包将使用这个数据类型的变量DateTime来保存在记录集列表中循环通过的符号的结束日期。

  • FileExtension:这个数据类型的变量String将保存用于下载文件的文件扩展名。这是可选的。

  • FileName:这个数据类型的变量String将保存给定符号的文件名。该名称是根据时间戳生成的,以避免覆盖以前下载的文件。单击变量并按F4查看属性。将属性更改EvaluateAsExpressionTrue。单击 Expression 上的Ellipsis按钮以打开Expression Builder。将 设置为以下值。此表达式的计算结果为类似,其中 MSFT 是符号,其余信息是格式中的包开始时间,并且是文件扩展名。ExpressionMSFT_20130210_092519.csvyyyMMdd_hhmmss.csv

@[User::Symbol] + "_" + (DT_WSTR, 4) YEAR(@[System::StartTime]) + RIGHT("00" + (DT_WSTR, 2) MONTH(@[System::StartTime]), 2) + RIGHT("00" + (DT_WSTR, 2) DAY(@[System::StartTime]), 2) + "_" + RIGHT("00" + (DT_WSTR, 2) DATEPART("hh", @ [System::StartTime]), 2) + RIGHT("00" + (DT_WSTR, 2) DATEPART("mi", @[System::StartTime]), 2) + RIGHT("00" + (DT_WSTR, 2) ) DATEPART("ss", @[System::StartTime]), 2) + @[User::FileExtension]

  • FilePath:这个数据类型的变量String将保存给定符号的下载文件的完整路径。单击变量并按F4查看属性。将属性更改EvaluateAsExpressionTrue。单击 Expression 上的 Ellipsis 按钮以打开Expression Builder。将 设置Expression为 值@[User::RootFolder] + "\\" + @[User::FileName]。我们将使用此快递

  • Resolution:包将使用这个数据类型的变量String来保存记录集列表中被循环通过的符号的解析信息。

  • RootFolder:这个数据类型的变量String将保存文件应该下载到的根文件夹。

  • SQL_GetSymbols:此数据类型变量String将包含 T-SQL 查询以从数据库中获取股票代码信息。将值设置为SELECT Symbol, StartDate, EndDate, Resolution FROM dbo.TickerSymbols

  • StartDate:包将使用这个数据类型的变量DateTime来保存在记录集列表中循环的符号的开始日期。

  • Symbol:包将使用此数据类型变量String来保存股票代码,因为它循环遍历记录集列表中的每条记录。

  • SymbolsList:包将使用这个数据类型的变量Object来保存存储在数据库中的股票代码的结果集。

  • URLYahooChart:这个数据类型的变量String将保存到 Yahoo Finance Chart 网站的 URL,并使用占位符填写查询字符串的适当值。将值设置为http://ichart.finance.yahoo.com/table.csv?s={0}&a={1}&b={2}&c={3}&d={4}&e={5}&f={6}&g={7}&ignore=.csv

变量

在包上,右键单击Connection Managers选项卡,然后单击Flat File Connection...

平面文件连接管理器

Flat File Connection Manager EditorGeneral页面上,执行以下操作:

  • 名称设置为FILE_TickerPriceHistory

  • 描述设置为Read the ticker symbol price history.

  • 如果您已有示例文件,请指向文件位置。SSIS 将从文件中的数据推断设置。在这种情况下,我已经通过导航 URL 下载了一个文件http://ichart.finance.yahoo.com/table.csv?s=MSFT&a=9&b=1&c=2012&d=11&e=30&f=2012&g=m&ignore=.csv并将其保存在名称下C:\Siva\StackOverflow\Files\14797886\Data\\MSFT_20130210_092519.csv

  • 确保格式设置为Delimited.

  • 确保标题行分隔符设置为{CR}{LF}

  • 选中该框Column names in the first data row

  • 单击页面

平面文件连接管理器编辑器 - 常规

Flat File Connection Manager EditorColumns页面上,确保 Row delimiter 设置为Column delimiter 设置为。单击高级页面。{LF}Comma {,}

平面文件连接管理器编辑器 - 列

Flat File Connection Manager EditorAdvanced页面上,将根据文件信息创建列。如下所示更改值,使列名与数据库中的名称匹配。这样列映射会更容易。除最后一列之外的所有列都应将ColumnDelimiter设置为。Lsst 列应将ColumnDelimiter设置为。Comma {,}{LF}

Column              Data type                            DataPrecision DataScale
------------------- ------------------------------------ ------------- ---------
PriceDate           date [DT_DATE]
PriceOpen           numeric [DT_NUMERIC]                      18          2
PriceHigh           numeric [DT_NUMERIC]                      18          2
PriceLow            numeric [DT_NUMERIC]                      18          2
PriceClose          numeric [DT_NUMERIC]                      18          2
Volume              eight-byte unsigned integer [DT_UI8]      
AdjustmentClose     numeric [DT_NUMERIC]                      18          2

平面文件连接管理器编辑器 - 高级

您现在应该在包底部看到两个连接管理器。

创建的连接管理器

将一个图标拖放Execute SQL TaskControl Flow选项卡上,然后在General选项卡上执行以下操作。

  • 名称设置为Get symbols from database
  • 描述设置为Fetch the list of symbols and its download settings from database.
  • ResultSet设置为,Full result set因为查询将返回记录集。
  • 连接类型设置为OLE DB
  • 连接设置为OLEDB_Sora
  • VariableSQLSourceType中选择
  • User::SQL_GetSymbols从源变量中选择
  • 单击结果集页面。

执行 SQL 任务 - 常规

在“执行 SQL 任务”的“结果集”页面,单击“添加”,并设置“结果名称”为结果集的索引。从变量名称中选择以将结果集存储到对象变量中。0User::SymbolsList

执行 SQL 任务 - 结果集

拖放一个Foreach 循环容器并将其放在Execute SQL Task之后。将执行 SQL 任务绿色箭头连接到 Foreach 循环容器。双击 Foreach 循环容器以查看 Foreach 循环编辑器。如下所示配置ForEach 循环编辑器。

ForEach 循环编辑器 - 集合

ForEach Loop Editor的 Variable Mappings 页面上进行如下配置:

ForEach 循环编辑器 - 变量映射

将 a 拖放Script Task到 ForEach 循环容器内。双击脚本任务以打开脚本任务编辑器。在脚本任务编辑器的脚本页面上,单击省略号按钮,ReadOnlyVariables然后选择下面列出的变量。我们需要在脚本任务代码中使用这些。

  • 用户::结束日期
  • 用户::文件扩展
  • 用户::文件名
  • 用户::文件路径
  • 用户::分辨率
  • 用户::根文件夹
  • 用户::开始日期
  • 用户::符号
  • 用户::URLYahooChart

脚本任务编辑器 - 脚本

单击脚本任务编辑器Edit Script...上的按钮并键入以下代码。输入代码后,关闭脚本任务编辑器。

C# 中的脚本任务代码:

using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using System.Net;

namespace ST_5fa66fe26d20480e8e3258a8fbd16683.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()
        {
            try
            {
                string symbol = Dts.Variables["User::Symbol"].Value.ToString();
                DateTime startDate = Convert.ToDateTime(Dts.Variables["User::StartDate"].Value);
                DateTime endDate = Convert.ToDateTime(Dts.Variables["User::EndDate"].Value);
                string resolution = Dts.Variables["User::Resolution"].Value.ToString();
                string urlYahooChart = Dts.Variables["User::URLYahooChart"].Value.ToString();

                string rootFolder = Dts.Variables["User::RootFolder"].Value.ToString();;
                string fileExtension = Dts.Variables["User::FileExtension"].Value.ToString();
                string fileName = Dts.Variables["User::FileName"].Value.ToString();
                string downloadPath = Dts.Variables["User::FilePath"].Value.ToString();

                if (!System.IO.Directory.Exists(rootFolder))
                    System.IO.Directory.CreateDirectory(rootFolder);

                urlYahooChart = string.Format(urlYahooChart
                                        , symbol
                                        , startDate.Month
                                        , startDate.Day
                                        , startDate.Year
                                        , endDate.Month
                                        , endDate.Day
                                        , endDate.Year
                                        , resolution);

                bool refire = false;
                Dts.Events.FireInformation(0, string.Format("Download URL of {0}", symbol), urlYahooChart, string.Empty, 0, ref refire);

                WebClient webClient = new WebClient();
                webClient.DownloadFile(urlYahooChart, downloadPath);

                Dts.TaskResult = (int)ScriptResults.Success;
            }
            catch (Exception ex)
            {
                Dts.Events.FireError(0, "Download error", ex.ToString(), string.Empty, 0);
            }
        }
    }
}

在Script Task之后将a 拖放Data Flow TaskForeach 循环容器内。将绿色箭头从 Script Task 连接到Data Flow Task。控制流选项卡应如下所示。

控制流选项卡

在数据流任务上,拖放平面文件源并按如下所示对其进行配置以读取价格历史 CSV 文件。

平面文件源 - 连接管理器

平面文件源 - 列

拖放 aDerived Column Transformation并创建一个以Symbol表达式命名的新列,(DT_STR,10,1252)@[User::Symbol]以将符号添加到数据管道。

派生列转换

拖放 OLE DB Destination 并按如下所示对其进行配置以将数据插入数据库。

OLE DB 目标 - 连接管理器

OLE DB 目标 - 映射

您的数据流选项卡应如下所示:

数据流选项卡

在运行包之前,我们需要进行一些更改,以防止由于文件夹中没有文件而在设计时视图上出现任何警告或错误。

单击平面文件连接管理器FILE_TickerPriceHistory并按下F4以查看属性。将属性更改DelayValidationTrue。这将确保文件存在的验证将在运行时发生。单击Expression上的Ellipsis按钮并将属性设置为 value 。这将在从网站下载每个文件时更改文件路径。ConnectionString@[User::FilePath]

平面文件连接管理器 - 延迟验证

单击数据流任务并按下F4以查看属性。将属性更改DelayValidationTrue。这将确保文件存在的验证将在运行时发生。

数据流任务 - DelayValidation

导航到数据流选项卡并单击平面文件源并按下F4以查看属性。将属性更改ValidateExternalMetadataFalse。这将确保在运行时验证平面文件是否存在。

平面文件源 - ValidateExternalMetadata

让我们导航到文件夹C:\Siva\StackOverflow\Files\14797886,将保存下载的文件的位置是空的。该文件夹不必为空。这仅用于执行检查。

下载文件夹为空

对数据库运行以下 SQL 语句以验证表中的数据。第二个表应该是空的。

SELECT * FROM dbo.TickerSymbols;
SELECT * FROM dbo.TickerPriceHistory;

执行前的表数据

执行包。如果一切设置正确,包应该成功运行并下载表中列出的每个符号的文件dbo.TickerSymbols

控制流执行

数据流执行

文件应成功保存到文件夹C:\Siva\StackOverflow\Files\14797886中。请注意,每个文件都根据包中提供的表达式适当地命名。

下载的文件

对数据库运行以下 SQL 语句以验证表中的数据。该表现dbo.TickerPriceHistory在应该包含从网站下载的价格文件中的数据。

SELECT * FROM dbo.TickerPriceHistory;

执行后的表数据

上面的示例包说明了如何从 Yahoo Finance Chart 网站下载给定股票代码列表的价格文件并将它们加载到数据库中。

于 2013-02-10T17:02:00.350 回答