【问题标题】:Import custom text format without separators [closed]导入不带分隔符的自定义文本格式[关闭]
【发布时间】:2015-04-25 22:29:11
【问题描述】:

我想将此 .txt 文件格式导入 SQL Server 表或将每个文本块转换为管道分隔行。

哪些工具或 C# 解决方案建议您解决此问题?

任何建议将不胜感激。

谢谢。

=================
INPUT (.txt file)
=================
ID: 37
Name: Josephy Murphy
Email: jmurphy@email.com
Description: bla, bla, bla, bla...

ID: 38
Name: Paul Newman
Email: pnewman@email.com
Description: bla, bla, bla, bla...

:
:

=========================
OUTPUT (SQL Server Table)
=========================

ID | Name           | Email             | Description  
37 | Josephy Murphy | jmurphy@email.com | bla, bla, bla, bla...
38 | Paul Newman    | pnewman@email.com | bla, bla, bla, bla...

:
: 

【问题讨论】:

  • 您尝试过什么,您自己尝试时遇到了什么问题?请注意,(1)“你建议使用哪些工具”在 SO 上是题外话,(2)“什么是做 X 的最佳方法”,其中可能有一百万个答案也是题外话,因为它会吸引固执己见答案以及广泛。我投票结束这个问题。请阅读how do i ask a good questionedit 你的答案。

标签: c# sql-server regex ssis etl


【解决方案1】:

我现在直接写入 SQL Server,而不是 DataTable。您需要在插入 SQL 中输入连接字符串和 SQL 表的名称。

如果你真的要添加那么多行,我会考虑使用 SQL Server 附带的 SQLCMD.EXE。它接受数据的任何分隔符和字符串 SQL。我从未将它与 Insert 一起使用,我通常将它用于 Select SQL。有许多不同的命令行可执行文件可与 SQL Server 一起使用。请参阅下面的网页 https://msdn.microsoft.com/en-us/library/ms162816.aspx

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.IO;
using System.Data.SqlClient;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.txt";
        enum States
        {
            FIND_OUTPUT,
            GET_SEPERATOR,
            GET_TABLE_HEADER,
            GET_DATA_TABLE,
            END
        }
        static void Main(string[] args)
        {
 
            States state = States.FIND_OUTPUT;
            StreamReader reader = new StreamReader(FILENAME);
            string inputLine = "";

            string connStr = "Enter your connection string here";
            SqlConnection conn = new SqlConnection(connStr);
            conn.Open();
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = conn;

            string[] headers = null;
            while ((inputLine = reader.ReadLine()) != null)
            {
                inputLine = inputLine.Trim();
                if (inputLine.Length > 0)
                {
                    switch (state)
                    {
                        case States.FIND_OUTPUT:
                            if (inputLine.StartsWith("OUTPUT (SQL Server Table)"))
                                state = States.GET_SEPERATOR;
                            break;
                        case States.GET_SEPERATOR:
                            state = States.GET_TABLE_HEADER;
                            break;
                        case States.GET_TABLE_HEADER:
                            headers = inputLine.Split(new char[] { '|'}, StringSplitOptions.RemoveEmptyEntries);
                            headers = headers.Select(x => x.Trim()).ToArray();
                            state = States.GET_DATA_TABLE;
                            break;
                        case States.GET_DATA_TABLE:
                            string[] dataArray = inputLine.Split(new char[] { '|'}, StringSplitOptions.RemoveEmptyEntries);
                            dataArray = dataArray.Select(x => x.Trim()).ToArray();
                            string commandText = string.Format("Insert into table1 ({0}) values ({1})", string.Join(",", headers), "'" + string.Join("','", dataArray) + "'");
                            cmd.CommandText = commandText;    
                            cmd.ExecuteNonQuery();
                            break;
                    }
                }
                else
                {
                    if (state == States.GET_DATA_TABLE)
                        break; //exit while loop if blank row at end of data table
                }
            }

            reader.Close();
            conn.Close();
        }
    }
}
​

【讨论】:

  • 您好!我需要将解决方案与 SSIS 一起使用。也就是将这4行转为一行,删除标签:ID:、Name:、Email:、Description:。使用脚本组件 SSIS 被认为是一个实用的解决方案。你怎么看?问题是转换(文本文件):(4行-> 1行没有标签)示例-> ID:37 姓名:Josephy Murphy 电子邮件:jmurphy@email.com 描述:bla,bla,bla,bla ... = >(CSV 结果): 37;Josephy Murphy;jmurphy@email.com;bla, bla, bla, bla... 你觉得呢?
  • 代码产生一行。
  • 我有一个 SQL Select 查询,我使用 SQLCMD.EXE 来获取大约 100 万行数据。查询运行大约需要 1/2 小时。我正在使用 SQLCMD.EXE,因为 VS 代码需要更长的时间。我会按照显示的顺序推荐以下内容。 1)如果旧数据库存在,则使用批量复制。您可以从 BCP.EXE 或 VS 运行批量复制。 2)使用VS将文件保存为BCP.EXE或SQLCMD.EXE可以读取的格式。您可以使用任何分隔符,包括“|”。或者将我的原始代码与数据表一起使用,并使用 WriteXML() 方法将结果保存到 XML。 3)按原样使用我最新的代码。
  • 使用 SSIS、SQLCMD.EXE 或 BCP.EXE 没有区别。这两个 .EXE 很好,因为您可以设置一个 BAT 文件来自动运行 SQL,而不是打开 GUI 并手动运行 SQL。完成任务的最佳方式是运行 C# 应用程序来创建 SSIS、SQLCMD.EXE 或 BCP 可以读取的文本文件。然后使用三种方法中的任何一种输入文本文件。
【解决方案2】:

解析这个文件非常简单。 40 年来一直在做这样的项目。请参阅下面的代码。我将结果放入 DataTable。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.txt";
        enum States
        {
            FIND_OUTPUT,
            GET_SEPERATOR,
            GET_TABLE_HEADER,
            GET_DATA_TABLE,
            END
        }
        static void Main(string[] args)
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("ID", typeof(int));
            dt.Columns.Add("Name", typeof(string));
            dt.Columns.Add("Email", typeof(string));
            dt.Columns.Add("Description", typeof(string));

            States state = States.FIND_OUTPUT;
            StreamReader reader = new StreamReader(FILENAME);
            string inputLine = "";
            while ((inputLine = reader.ReadLine()) != null)
            {
                inputLine = inputLine.Trim();
                if (inputLine.Length > 0)
                {
                    switch (state)
                    {
                        case States.FIND_OUTPUT:
                            if (inputLine.StartsWith("OUTPUT (SQL Server Table)"))
                                state = States.GET_SEPERATOR;
                            break;
                        case States.GET_SEPERATOR:
                            state = States.GET_TABLE_HEADER;
                            break;
                        case States.GET_TABLE_HEADER:
                            state = States.GET_DATA_TABLE;
                            break;
                        case States.GET_DATA_TABLE:
                            string[] dataArray = inputLine.Split(new char[] { '|' });
                            dt.Rows.Add(dataArray);
                            break;
                    }
                }
                else
                {
                    if (state == States.GET_DATA_TABLE)
                        break; //exit while loop if blank row at end of data table
                }
            }

            reader.Close();
        }
    }
}
​

【讨论】:

  • 恭喜!阅读代码我了解程序结构的逻辑。你知道有什么工具可以将这个导入到 SQL Sever 中吗? (性能 - 15,000,000 行阅读)...
【解决方案3】:

Python 简单:

input='''\
ID: 37
Name: Josephy Murphy
Email: jmurphy@email.com
Description: bla, bla, bla, bla...

ID: 38
Name: Paul Newman
Email: pnewman@email.com
Description: bla, bla, bla, bla...'''

import re
fields=('ID', 'Name', 'Email', 'Description')
out={k:[] for k in fields}
for m in re.finditer(r'(^ID.*?(?=^ID|\Z))', input, flags=re.S | re.M):
    for k, v in [map(str.strip, line.split(':')) for line in m.group(1).splitlines() if line.strip()]:
        out[k].append(v)

# you now have all the data in a structure that could be used with SQL
# just print to show...    
fmt='{:3}| {:20}| {:20}| {:20}'
print fmt.format(*fields)    
for i in range(len(out['ID'])):
    print fmt.format(*[out[k][i] for k in fields])  

打印:

ID | Name                | Email               | Description         
37 | Josephy Murphy      | jmurphy@email.com   | bla, bla, bla, bla...
38 | Paul Newman         | pnewman@email.com   | bla, bla, bla, bla...

【讨论】:

  • 恭喜!不幸的是,我不懂 Python。你知道有什么工具可以将这个导入到 SQL Sever 中吗? (性能 - 15,000,000 行阅读)...
猜你喜欢
  • 2014-08-17
  • 1970-01-01
  • 1970-01-01
  • 2016-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-21
  • 1970-01-01
相关资源
最近更新 更多