2

我每隔几个月左右使用一次 F#,在这期间我似乎忘记了一切,所以我希望你能原谅我的无知。我下面的代码是从雅虎提取数据。这是一个很好的例子,代表了我需要做的事情。返回的第一行具有列标题。我需要获取数据(列表的尾部)并将其插入数据库。根据返回的列标题(列标题与数据库列名匹配)生成插入语句的最佳方法是什么?

在下面的示例中 dataWithHeaders.[0] 将包含“日期、打开、高、低、关闭、音量、调整关闭”。我是否应该只使用该字符串并在标题周围加上括号来创建插入?然后在 insertData 添加值作为参数?有没有更优雅的解决方案?

let url = System.String.Format("http://ichart.finance.yahoo.com/table.csv?s={0}&g=d&ignore=.csv", "FB")

let splitLineIntoArray (line : string) = 
    line.Split(",".ToCharArray())

let insertData (data : string[]) =
    // insert data
    ()

let client = new WebClient()
let dataWithHeaders = 
    client.DownloadString(url).Split(Environment.NewLine.ToCharArray())

let data =
    dataWithHeaders
    |> Array.toList
    |> List.tail
    |> List.map(splitLineIntoArray)
    |> List.iter insertData
4

2 回答 2

8

If you're loading the data into SQL Server you can use this excellent CSV reader (free) and the SqlBulkCopy class. It's simple and efficient.

let loadStockPrices ticker =
  use client = new WebClient()
  let url = sprintf "http://ichart.finance.yahoo.com/table.csv?s=%s&g=d&ignore=.csv" ticker
  use stringReader = new StringReader(client.DownloadString(url))
  use csvReader = new CsvReader(stringReader, hasHeaders=true)
  use con = new SqlConnection("<connection_string>")
  con.Open()
  use bulkCopy = new SqlBulkCopy(con, DestinationTableName="<destination_table>")
  bulkCopy.WriteToServer(csvReader)

The destination table should have the same columns as the incoming data (OHLC, etc).

于 2012-07-26T20:18:16.843 回答
4

编辑:类型提供者可能是一个不错的方法,但 SqlBulkCopy 是定义。以其简单而闻名。

为插入键入提供程序代码:http: //msdn.microsoft.com/en-us/library/hh361033 (v=vs.110).aspx#BKMK_UpdateDB

type dbSchema = SqlDataConnection<"Data Source=MYSERVER\INSTANCE;Initial Catalog=MyDatabase;Integrated Security=SSPI;">
let db = dbSchema.GetDataContext()

// Enable the logging of database activity to the console.
db.DataContext.Log <- System.Console.Out

let newRecord = new dbSchema.ServiceTypes.Table1(Id = 100,
                                                 TestData1 = 35, 
                                                 TestData2 = 2.0,
                                                 Name = "Testing123")
let newValues =
    [ for i in [1 .. 10] ->
          new dbSchema.ServiceTypes.Table3(Id = 700 + i,
                                           Name = "Testing" + i.ToString(),
                                           Data = i) ]
// Insert the new data into the database.
db.Table1.InsertOnSubmit(newRecord)
db.Table3.InsertAllOnSubmit(newValues)
try
    db.DataContext.SubmitChanges()
    printfn "Successfully inserted new rows."
with
   | exn -> printfn "Exception:\n%s" exn.Message

我做了类似的事情。实际上,这段代码是我在观看 Luca Bolognese 的 F# 演示时编写的。这实际上会刮掉雅虎的提要并返回标准开发。和股票价格的差异。

完整项目在这里:https ://github.com/djohnsonm/Stock-Ticker-App

open System.Net
open System.IO

let internal loadPrices ticker = async {
let url = @"http://ichart.finance.yahoo.com/table.csv?s=" + ticker + "&d=6&e=22&f=2011&g=d&a=2&b=13&c=1986&ignore=.csv"
let req = WebRequest.Create(url)
let resp = req.GetResponse()
let stream = resp.GetResponseStream()
let reader = new StreamReader(stream)
let csv = reader.ReadToEnd()
let prices = 
    csv.Split([|'\n'|])
    |> Seq.skip 1
    |> Seq.map (fun line -> line.Split([|','|]))
    |> Seq.filter(fun values -> values |> Seq.length = 7)
    |> Seq.map(fun values ->
        System.DateTime.Parse(values.[0]),
        float values.[6])
return prices}

type StockAnalyzer (lprices, days) =
    let prices =
        lprices
        |> Seq.map snd
        |> Seq.take days
    static member GetAnalyzers (tickers, days) =
        tickers
        |> Seq.map loadPrices
        |> Async.Parallel
        |> Async.RunSynchronously
        |> Seq.map (fun prices -> new StockAnalyzer(prices, days))
    member s.Return =
        let lastPrice = prices |> Seq.nth 0
        let startPrice = prices |> Seq.nth(days-1)
        lastPrice / startPrice - 1.
    member s.StdDev =
        let logRets =
            prices
            |> Seq.pairwise
            |> Seq.map (fun (x,y) -> log(x/y))
        let mean = logRets |> Seq.average
        let sqr x = x * x
        let var = logRets |> Seq.averageBy (fun r -> sqr (r-mean))
        sqrt var
于 2012-07-26T20:06:25.970 回答