簡體   English   中英

使用Filehelpers,將大型CSV文件導入SQL2014表

[英]Using Filehelpers, import large CSV file into SQL2014 table

CSV文件以逗號分隔,包含嵌入式分隔符和引號。 有些字段的開頭和結尾都有引號,有些則沒有。

完美處理了第一條記錄,但第二條記錄卻處理不了。 如您所見,該字段似乎有引號,但實際上是嵌入的。 field5沒有尾隨引號。 導入的結果將空白放在字段5和6中,並將field5數據(以粗體顯示)推入field7中,此過程稍后會導致違反“最大字段長度”。

Filehelpers中是否可以使用屬性設置來處理包含以下以粗體字母表示的字段的記錄,以便該記錄正確導入每個字段? CSV文件是從外部來源收到的,因此我無法控制Feed。

AT2M-2471-3,“ 1178”,AccuTemp,48“”整體切菜板(必須與AT2A-2630-3或AT2A-2630-22一起訂購),, ea,“ 10.00”,“ 0.00000”,“ 207.00 “,” 93.41“,” 0.00“,” 0.00“,” 0.00“,” 0.00“,ATCUT,”“,” 1“,每個,”切割板,已安裝設備“,Accutemp,”“,” False“, ,85 “” ,, “0”, “baab3369-BCAD-453e-9867-921e4af1203c”, “”,Accutemp ,, “”, “e0fb1dfb-c00d-DD11-a23a-00304834a8c9”,“bcd6e7a0-be0d-DD11 -a23a-00304834a8c9"

AT2M-2877-1,“” 1178“,AccuTemp, ”“ U”“通道,用於連接兩個29”“ A深度烤盤 ,, ea,” 4.00“,” 0.00000“,” 104.00“,” 46.93“,” 0.00 “ ”0.00“, ”0.00“, ”0.00“,AT2M, ”“, ”1“,每個,, Accutemp, ”“, ”假“ ,, 85 ”“ ,, ”0“,” f7d56cb1-b2ab -40c7-b7e5-55ee1b4d1023" , “”,Accutemp ,, “”, “e3fb1dfb-c00d-DD11-a23a-00304834a8c9”, “bcd6e7a0-be0d-DD11-a23a-00304834a8c9”

這是SQL表結構,沒有索引:

    CREATE TABLE [dbo].[rawdata](
        [Model Number] [varchar](50) NULL,
        [User Stock Model Number] [varchar](50) NULL,
        [Vendor Number] [varchar](50) NULL,
        [Vendor Name] [varchar](50) NULL,
        [Specification] [varchar](max) NULL,
        [Vendor Pack] [varchar](50) NULL,
        [Selling Unit] [varchar](50) NULL,
        [Weight] [varchar](50) NULL,
        [Cube] [varchar](50) NULL,
        [List Price] [varchar](50) NULL,
        [Net Price] [varchar](50) NULL,
        [Height] [varchar](50) NULL,
        [Width] [varchar](50) NULL,
        [Depth] [varchar](50) NULL,
        [Deal Net] [varchar](50) NULL,
        [Picture Name] [varchar](150) NULL,
        [Blank Column] [varchar](50) NULL,
        [Vendor to Stock] [varchar](50) NULL,
        [Priced By] [varchar](50) NULL,
        [Category] [varchar](75) NULL,
        [Vendor Nickname] [varchar](50) NULL,
        [User Vendor Name] [varchar](50) NULL,
        [Configurable?] [varchar](50) NULL,
        [Category Values] [varchar](max) NULL,
        [Freight Class] [varchar](50) NULL,
        [Vendor FOB] [varchar](50) NULL,
        [Ship from Zip] [varchar](50) NULL,
        [Model Apply] [varchar](50) NULL,
        [Picture Link] [varchar](50) NULL,
        [Category Code] [varchar](50) NULL,
        [Vendor Short Name] [varchar](50) NULL,
        [Cutsheet Name] [varchar](150) NULL,
        [Cutsheet Link] [varchar](50) NULL,
        [Product ID] [varchar](50) NULL,
        [Vendor ID] [varchar](50) NULL
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

我為表創建了具有以下屬性的類:[DelimitedRecord(“,”)] [IgnoreFirst(1)]

class rawdata
{
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Model_Number;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string User_Stock_Model_Number;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Vendor_Number;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Vendor_Name;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Specification;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Vendor_Pack;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Selling_Unit;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Weight;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Cube;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string List_Price;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Net_Price;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Height;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Width;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Depth;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Deal_Net;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Picture_Name;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Blank_Column;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Vendor_to_Stock;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Priced_By;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Category;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Vendor_Nickname;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string User_Vendor_Name;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Configurable;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Category_Values;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Freight_Class;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Vendor_FOB;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Ship_from_Zip;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Model_Apply;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Picture_Link;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Category_Code;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Vendor_Short_Name;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Cutsheet_Name;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Cutsheet_Link;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Product_ID;
    [FieldQuoted('"', QuoteMode.OptionalForBoth)] // Optional quoted when read or write
    public string Vendor_ID;  

}

這是C#代碼:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Threading.Tasks;
    using System.Data;
    using System.Data.SqlClient;
    using System.Windows.Forms;
    using FileHelpers;

    namespace XYZ
    {
        class Class1
        {
            static void Main(string[] args)
            {
                SqlConnection conn1 = new SqlConnection();
                DataTable temp_rawdata_table = new DataTable();

                conn1.ConnectionString = "Data Source=ABC;Initial Catalog=XYZ;Integrated Security=True";

                System.Diagnostics.Stopwatch elapsed = new System.Diagnostics.Stopwatch();
                elapsed.Start(); Int64 rows = 0;

                // ================ Begin BulkCopy ========================
                using (SqlBulkCopy bulkcopy = new SqlBulkCopy(conn1.ConnectionString,
                    System.Data.SqlClient.SqlBulkCopyOptions.TableLock)
                    {
                        DestinationTableName = "rawdata",
                        BulkCopyTimeout = 0,
                        BatchSize = 100000
                    })
                {
                    temp_rawdata_table = new XYZDataSet.rawdataDataTable();

                    // using the ASYNC engine allows for processing record by record
                    FileHelperAsyncEngine engine = new FileHelperAsyncEngine(typeof(rawdata));
                    engine.BeginReadFile("C:\\rawdata.csv");

                    int batchsize = 0;

                    Console.WriteLine("Copying data to table.");
                    // The Async engines are IEnumerable
                    foreach (rawdata aqtext in engine)
                    {
                        //create a new update row for aq360productsraw table
                        DataRow rawdata_update_row = temp_rawdata_table.NewRow();

                        rawdata_update_row["Model Number"] = aqtext.Model_Number.Trim();
                        rawdata_update_row["User Stock Model Number"] = aqtext.User_Stock_Model_Number.Trim();
                        rawdata_update_row["Vendor Number"] = aqtext.Vendor_Number.Trim();
                        rawdata_update_row["Vendor Name"] = aqtext.Vendor_Name.Trim();
                        rawdata_update_row["Specification"] = aqtext.Specification.Trim();
                        rawdata_update_row["Vendor Pack"] = aqtext.Vendor_Pack.Trim();
                        rawdata_update_row["Selling Unit"] = aqtext.Selling_Unit.Trim();
                        rawdata_update_row["Weight"] = aqtext.Weight.Trim();
                        rawdata_update_row["Cube"] = aqtext.Cube.Trim();
                        rawdata_update_row["List Price"] = aqtext.List_Price.Trim();
                        rawdata_update_row["Net Price"] = aqtext.Net_Price.Trim();
                        rawdata_update_row["Height"] = aqtext.Height.Trim();
                        rawdata_update_row["Width"] = aqtext.Width.Trim();
                        rawdata_update_row["Depth"] = aqtext.Depth.Trim();
                        rawdata_update_row["Deal Net"] = aqtext.Deal_Net.Trim();
                        rawdata_update_row["Picture Name"] = aqtext.Picture_Name.Trim();
                        rawdata_update_row["Blank Column"] = aqtext.Blank_Column.Trim();
                        rawdata_update_row["Vendor to Stock"] = aqtext.Vendor_to_Stock.Trim();
                        rawdata_update_row["Priced By"] = aqtext.Priced_By.Trim();
                        rawdata_update_row["Category"] = aqtext.Category.Trim();
                        rawdata_update_row["Vendor Nickname"] = aqtext.Vendor_Nickname.Trim();
                        rawdata_update_row["User Vendor Name"] = aqtext.User_Vendor_Name.Trim();
                        rawdata_update_row["Configurable?"] = aqtext.Configurable.Trim();
                        rawdata_update_row["Category Values"] = aqtext.Category_Values.Trim();
                        rawdata_update_row["Freight Class"] = aqtext.Freight_Class.Trim();
                        rawdata_update_row["Vendor FOB"] = aqtext.Vendor_FOB.Trim();
                        rawdata_update_row["Ship from Zip"] = aqtext.Ship_from_Zip.Trim();
                        rawdata_update_row["Model Apply"] = aqtext.Model_Apply.Trim();
                        rawdata_update_row["Picture Link"] = aqtext.Picture_Link.Trim();
                        rawdata_update_row["Category Code"] = aqtext.Category_Code.Trim();
                        rawdata_update_row["Vendor Short Name"] = aqtext.Vendor_Short_Name.Trim();
                        rawdata_update_row["Cutsheet Name"] = aqtext.Cutsheet_Name.Trim();
                        rawdata_update_row["Cutsheet Link"] = aqtext.Cutsheet_Link.Trim();
                        rawdata_update_row["Product ID"] = aqtext.Product_ID.Trim();
                        rawdata_update_row["Vendor ID"] = aqtext.Vendor_ID.Trim();


                        temp_rawdata_table.Rows.Add(rawdata_update_row);

                        batchsize += 1;
                        if (batchsize == 100000)
                        {
                            bulkcopy.WriteToServer(temp_rawdata_table);
                            temp_rawdata_table.Rows.Clear();
                            batchsize = 0;
                            Console.WriteLine("Flushing 100,000 rows");
                        }

                        rows += 1;

                        Console.WriteLine(rows.ToString() + "    " + aqtext.Model_Number.Trim() + Environment.NewLine);
                    }


                    bulkcopy.WriteToServer(temp_rawdata_table);
                    temp_rawdata_table.Rows.Clear();

                    engine.Close();
                }
                elapsed.Stop();
                Console.WriteLine((rows + " records imported in " +  elapsed.Elapsed.TotalSeconds + " seconds."));
            }
        }
    }

@MarcosMeli也提到過,問題是這是無效的CSV文件。 不僅限於那個領域。 甚至您認為正在運行的行也沒有真正運行。 似乎是誰創建了這個CSV文件,都是按照哪些字段應該用文本限定(即“帶引號”)和哪些不需要的來做到這一點。 它們的數字字段是文本限定的,文本字段是非限定的。

第1行起作用的原因是,文本限定條件會查看該字段的第一個和最后一個字符。 在第1行中,轉義引號(即雙精度雙引號)不是第一個字符,因此我懷疑它是作為重復的雙引號導入的。 但是在第2行中,該字段的起始文本被引用了,因此第一個字符是一個引號,然后他們通過重復雙引號來轉義。 它非常草率地完成,即使現在讓FileHelpers使用它也不能使它繼續正常工作,這對它沒有太大的信心,特別是如果非文本限定的文本字段中包含逗號。 在這種情況下,它將再次導致字段中的意外變化。 我知道您說過CSV文件來自外部資源,您無法控制它,但是您確實需要嘗試將其修復,因為它是完全錯誤的。 無論在哪個系統中生成它,它都是一個錯誤,需要對其進行修復。

目前,您可以將所有文本字段設置為非文本限定。 但是,您可能需要添加一個步驟,用一個雙引號替換所有雙引號。


除了數據格式問題外,而且它看起來像是一個有趣且有用的庫,因此它不會占用FileHelpers的任何東西,我會說您不需要 FileHelpers來逐行讀取文本文件(最小內存占用),並且將其批處理到SQL Server中。 實際上,您可以做到所有這些加法:

  • 跳過擁有單獨的臨時表(即[rawdata] )的步驟,而是直接將行發送到同步存儲過程中
  • 在應用程序層中進行基本的數據類型驗證,並發送強類型的數據行(而不是傳遞所有VARCHAR / NVARCHAR字段)。

怎么會這樣? 通過使用表值參數, 使用IEnumerable<SqlDataRecord>方法(而不是 DataTable方法)將其傳遞。 我在這里的一些答案中詳細介紹了該技術:

問題是CSV無效,只有在字段被加引號的情況下才可以對引號進行轉義

價值:

,""U"" channel for connecting two 29"" A Depth griddles,

要正確解析,必須

,"""U"" channel for connecting two 29"" A Depth griddles",

從規范字段中刪除FieldQuoted怎么辦?

  public string Specification;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM