读取 TXT 文件并将其转换为 SQL 脚本
Read a TXT file and transform it into a SQL script
我有一个 txt 文件:
LoginId; No_Intervenant
EF2KBT0; 1003820030
ENHD0KE; 1003820129
E9PM7EP; 1003820153
EFT10OO; 1003820218
我需要创建另一个 txt 文件,其中包含来自以下信息的 sql 更新脚本:
UPDATE Contact
Set
Contact.No_Intervenant = '1003820030'
where
ISNULL (Contact.LoginId, '') = 'ER7OZXZ';
我只使用 Stringbuilder
方法得到了这个结果,但执行了硬编码。我想要的是自动添加 header。
public Form1()
{
InitializeComponent();
}
private static void AddSqlCommand(StringBuilder sql, string[] columns, string[] types, string[] values)
{
sql.AppendLine("UPDATE Contact");
sql.AppendLine("SET");
//skip LoginId columns
for (int i = 1; i < columns.Length; i++)
{
switch (types[i].Trim())
{
case "int":
sql.Append($" Contact.{columns[i].Trim()} = {values[i]}");
//sql.Append($" Contact.{columns[0].TrimStart() } = {values[i]}");
break;
default:
sql.Append($" Contact.No_Intervenant = '{values[i]}'");
break;
}
if (columns.Length > 1 && i != columns.Length - 1)
{
sql.Append(",");
}
sql.AppendLine();
}
sql.AppendLine("WHERE");
sql.AppendLine($" ISNULL(Contact.LoginId, '') = '{values[0]}';");
sql.AppendLine();
}
private static StringBuilder GenerateSqlScript(string[] fileContent)
{
var sqlCommand = new StringBuilder();
string[] types = fileContent[0].Split(';');
string[] columns = fileContent[1].Split(';');
//skip the first line (header)
for (int i = 2; i < fileContent.Length; i++)
{
string[] values = fileContent[i].Split(';');
if (values.Length >= 1)
{
AddSqlCommand(sqlCommand, columns, types, values);
}
}
return sqlCommand;
}
如何自动获取并添加 header?因为我可能必须为更长的文件执行此操作,其他文件有更多的列和更多的更新行,而且我不想硬编码文件的所有 headers,就像我将拥有的示例下一步:
Header:
No_Intervenant;First_Name;Last_Name;Role_SE;EMail;Phone;Extension;Statut;Address_1;Address_2;Zip;CPF;Inscription_Particulier;DHM_Stat_Part;Date_via_ClicSeQur;Last_Update;
数据:
1003820030;NOEL;SANTOS;Particulier;;;;Actif;1528 STREET;VAL-D''OR CA;AAA 5T9;123456789;Actif;;2016-07-19 09:49:43;2019-02-08 14:24:19;
我相信您只需要对字符串插值进行一些简单的更改,请参见下文。如果您有一个影响多个 table 的更新,您应该将您的 table 名称附加到数组中的列。
我是这样测试的,根据你的逻辑,文件的第一行应该包含你的数据类型(你发布的例子没有)。所以要么你的逻辑错了,要么数据样本错了。它适用于测试代码。
private void button4_Click(object sender, EventArgs e)
{
var line = new List<string>();
line.Add("string;string");
line.Add("LoginId; No_Intervenant");
line.Add("EF2KBT0; 1003820030");
line.Add("ENHD0KE; 1003820129");
line.Add("E9PM7EP; 1003820153");
line.Add("EFT10OO; 1003820218");
var fileContent = line.ToArray();
var sqlCommand = new StringBuilder();
string[] types = fileContent[0].Split(';');
string[] columns = fileContent[1].Split(';');
//skip the first line (header)
for (int i = 2; i < fileContent.Length; i++)
{
string[] values = fileContent[i].Split(';');
if (values.Length >= 1)
{
AddSqlCommand(sqlCommand, columns, types, values, "client");
}
}
}
编辑函数:
private static void AddSqlCommand(StringBuilder sql, string[] columns, string[] types, string[] values, string table)
{
sql.AppendLine($"UPDATE {table}");
sql.AppendLine("SET");
//skip LoginId columns
for (int i = 1; i < columns.Length; i++)
{
switch (types[i].Trim())
{
case "int":
sql.Append($" {columns[i].Trim()} = {values[i]}");
break;
default:
sql.Append($" {columns[i].Trim()} = '{values[i]}'");
break;
}
if (columns.Length > 1 && i != columns.Length - 1)
{
sql.Append(",");
}
sql.AppendLine();
}
sql.AppendLine("WHERE");
sql.AppendLine($" ISNULL({columns[0].Trim()}, '') = '{values[0]}';");
sql.AppendLine();
}
}
我相信在这种情况下 'MERGE' 将是一个完美的解决方案。
它可能是这样的:
-- HEADER --
MERGE [your table] as trg
USING (VALUES
-- DATA FROM THE FILE --
(id, intervenant),
(id, intervenant)
-- FOOTER
) as src(id, intervenant)
ON [your logic from the WHERE statement]
WHEN MATCHED UPDATE SET
trg.[your column] = src.[your column];
可以将源文件中的数据加载到 DataTable
object 中,然后使用 UPDATE
语句从中构建。文件中的 header 名称是从 DataTable
的 Columns
属性 中获得的,然后用于指定 UPDATE
脚本中使用的列。在下面的示例中,在脚本中添加了额外的行和 GO
分隔符以进行格式化。这些不是必需的,如果您愿意,可以将其删除。
using System.Linq;
using System.Data;
using System.IO;
using System.Text;
//get source file
string fullFileName = @"C:\Input Folder\SourceFile.txt";
DataTable dt = new DataTable();
StringBuilder sb = new StringBuilder();
//output .sql script
string sqlScript = @"C:\Output Folder\UpdateScript.SQL";
using (StreamReader sr = new StreamReader(fullFileName))
{
string firstLine = sr.ReadLine();
string[] headers = firstLine.Split(';');
//define columns for data table
foreach (string h in headers)
{
dt.Columns.Add(h);
}
int columnCount = dt.Columns.Count;
string line = sr.ReadLine();
while (line != null)
{
string[] fields = line.Split(';');
int currentLength = fields.Count();
if (currentLength < columnCount)
{
while (currentLength < columnCount)
{
line += sr.ReadLine();
currentLength = line.Split(';').Count();
}
fields = line.Split(';');
}
//load data table
dt.Rows.Add(fields);
line = sr.ReadLine();
}
foreach (DataRow dr in dt.Rows)
{
sb.AppendLine("UPDATE Contact SET " + dt.Columns[1] + " = '" + dr[1] +
"' WHERE ISNULL(" + dt.Columns[0] + ", '') = '" + dr[0] + "'");
//extra lines and GO batch separator added between UPDATE statements for formating
sb.AppendLine(Environment.NewLine);
sb.AppendLine("GO");
sb.AppendLine(Environment.NewLine);
}
//output UPDATE commands as .sql script file
File.WriteAllText(sqlScript, sb.ToString());
}
只是为了 post 我更新的代码更新,目前可以完美运行。谢谢大家的回答和帮助。
using System;
using System.IO;
using System.Text;
using System.Windows.Forms;
namespace GenererScriptSQL
{
public 部分 class Form1 : 表格
{
public 表格 1()
{
初始化组件();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private static void AddSqlCommand(StringBuilder sql, string[] columns, string[] types, string[] values)
{
sql.AppendLine("UPDATE Contact");
sql.AppendLine("SET");
//skip LoginId columns
for (int i = 1; i < columns.Length; i++)
{
switch (types[i].Trim())
{
case "int":
sql.Append($" Contact.{columns[i].Trim()} = {values[i]}");
break;
default:
sql.Append($" Contact.{columns[i].Trim()} = '{values[i]}'");
break;
}
if (columns.Length > 1 && i != columns.Length - 1)
{
sql.Append(",");
}
sql.AppendLine();
}
sql.AppendLine();
sql.AppendLine("WHERE");
sql.AppendLine();
sql.AppendLine($" Contact.{columns[0].Trim()} = '{values[0]}'");
sql.AppendLine();
}
private static StringBuilder GenerateSqlScript(string[] fileContent)
{
var sqlCommand = new StringBuilder();
string[] types = fileContent[0].Split(';');
string[] columns = fileContent[0].Split(';');
//skip the first line(header)
for (int i = 1; i < fileContent.Length; i++)
{
string[] values = fileContent[i].Split(';');
if (values.Length >= 1)
{
AddSqlCommand(sqlCommand, columns, types, values);
}
}
return sqlCommand;
}
private void buttonCreateSqlFile_Click(object sender, EventArgs e)
{
try
{
if (IsFileSelected())
{
string[] fileContent = File.ReadAllLines(textBoxFile.Text);
if (fileContent != null)
{
StringBuilder sqlCommand = GenerateSqlScript(fileContent);
if (!string.IsNullOrWhiteSpace(sqlCommand.ToString()))
{
WriteSqlFile(sqlCommand);
}
}
}
else
{
MessageBox.Show("Sélectionner le fichier de chargement.");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void buttonSelectFile_Click(object sender, EventArgs e)
{
try
{
using (var fileBrowser = new OpenFileDialog())
{
if (fileBrowser.ShowDialog() == DialogResult.OK)
{
textBoxFile.Text = fileBrowser.FileName;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private bool IsFileSelected()
{
return !string.IsNullOrWhiteSpace(textBoxFile.Text) && File.Exists(textBoxFile.Text);
}
private void WriteSqlFile(StringBuilder sqlCommand)
{
var fileInfo = new FileInfo(textBoxFile.Text);
string BackupDate = fileInfo.Name + "_" + DateTime.Now.ToString("yyyy-MM-dd_HH-mm") + "_Update" + ".sql";
string sqlFilePath = Path.Combine(fileInfo.Directory.FullName, BackupDate);
if (File.Exists(sqlFilePath))
{
File.Delete(sqlFilePath);
}
File.WriteAllText(sqlFilePath, sqlCommand.ToString());
MessageBox.Show($@" Le fichier sql a été générée! {sqlFilePath}");
}
}
}
我有一个 txt 文件:
LoginId; No_Intervenant
EF2KBT0; 1003820030
ENHD0KE; 1003820129
E9PM7EP; 1003820153
EFT10OO; 1003820218
我需要创建另一个 txt 文件,其中包含来自以下信息的 sql 更新脚本:
UPDATE Contact
Set
Contact.No_Intervenant = '1003820030'
where
ISNULL (Contact.LoginId, '') = 'ER7OZXZ';
我只使用 Stringbuilder
方法得到了这个结果,但执行了硬编码。我想要的是自动添加 header。
public Form1()
{
InitializeComponent();
}
private static void AddSqlCommand(StringBuilder sql, string[] columns, string[] types, string[] values)
{
sql.AppendLine("UPDATE Contact");
sql.AppendLine("SET");
//skip LoginId columns
for (int i = 1; i < columns.Length; i++)
{
switch (types[i].Trim())
{
case "int":
sql.Append($" Contact.{columns[i].Trim()} = {values[i]}");
//sql.Append($" Contact.{columns[0].TrimStart() } = {values[i]}");
break;
default:
sql.Append($" Contact.No_Intervenant = '{values[i]}'");
break;
}
if (columns.Length > 1 && i != columns.Length - 1)
{
sql.Append(",");
}
sql.AppendLine();
}
sql.AppendLine("WHERE");
sql.AppendLine($" ISNULL(Contact.LoginId, '') = '{values[0]}';");
sql.AppendLine();
}
private static StringBuilder GenerateSqlScript(string[] fileContent)
{
var sqlCommand = new StringBuilder();
string[] types = fileContent[0].Split(';');
string[] columns = fileContent[1].Split(';');
//skip the first line (header)
for (int i = 2; i < fileContent.Length; i++)
{
string[] values = fileContent[i].Split(';');
if (values.Length >= 1)
{
AddSqlCommand(sqlCommand, columns, types, values);
}
}
return sqlCommand;
}
如何自动获取并添加 header?因为我可能必须为更长的文件执行此操作,其他文件有更多的列和更多的更新行,而且我不想硬编码文件的所有 headers,就像我将拥有的示例下一步:
Header:
No_Intervenant;First_Name;Last_Name;Role_SE;EMail;Phone;Extension;Statut;Address_1;Address_2;Zip;CPF;Inscription_Particulier;DHM_Stat_Part;Date_via_ClicSeQur;Last_Update;
数据:
1003820030;NOEL;SANTOS;Particulier;;;;Actif;1528 STREET;VAL-D''OR CA;AAA 5T9;123456789;Actif;;2016-07-19 09:49:43;2019-02-08 14:24:19;
我相信您只需要对字符串插值进行一些简单的更改,请参见下文。如果您有一个影响多个 table 的更新,您应该将您的 table 名称附加到数组中的列。
我是这样测试的,根据你的逻辑,文件的第一行应该包含你的数据类型(你发布的例子没有)。所以要么你的逻辑错了,要么数据样本错了。它适用于测试代码。
private void button4_Click(object sender, EventArgs e)
{
var line = new List<string>();
line.Add("string;string");
line.Add("LoginId; No_Intervenant");
line.Add("EF2KBT0; 1003820030");
line.Add("ENHD0KE; 1003820129");
line.Add("E9PM7EP; 1003820153");
line.Add("EFT10OO; 1003820218");
var fileContent = line.ToArray();
var sqlCommand = new StringBuilder();
string[] types = fileContent[0].Split(';');
string[] columns = fileContent[1].Split(';');
//skip the first line (header)
for (int i = 2; i < fileContent.Length; i++)
{
string[] values = fileContent[i].Split(';');
if (values.Length >= 1)
{
AddSqlCommand(sqlCommand, columns, types, values, "client");
}
}
}
编辑函数:
private static void AddSqlCommand(StringBuilder sql, string[] columns, string[] types, string[] values, string table)
{
sql.AppendLine($"UPDATE {table}");
sql.AppendLine("SET");
//skip LoginId columns
for (int i = 1; i < columns.Length; i++)
{
switch (types[i].Trim())
{
case "int":
sql.Append($" {columns[i].Trim()} = {values[i]}");
break;
default:
sql.Append($" {columns[i].Trim()} = '{values[i]}'");
break;
}
if (columns.Length > 1 && i != columns.Length - 1)
{
sql.Append(",");
}
sql.AppendLine();
}
sql.AppendLine("WHERE");
sql.AppendLine($" ISNULL({columns[0].Trim()}, '') = '{values[0]}';");
sql.AppendLine();
}
}
我相信在这种情况下 'MERGE' 将是一个完美的解决方案。 它可能是这样的:
-- HEADER --
MERGE [your table] as trg
USING (VALUES
-- DATA FROM THE FILE --
(id, intervenant),
(id, intervenant)
-- FOOTER
) as src(id, intervenant)
ON [your logic from the WHERE statement]
WHEN MATCHED UPDATE SET
trg.[your column] = src.[your column];
可以将源文件中的数据加载到 DataTable
object 中,然后使用 UPDATE
语句从中构建。文件中的 header 名称是从 DataTable
的 Columns
属性 中获得的,然后用于指定 UPDATE
脚本中使用的列。在下面的示例中,在脚本中添加了额外的行和 GO
分隔符以进行格式化。这些不是必需的,如果您愿意,可以将其删除。
using System.Linq;
using System.Data;
using System.IO;
using System.Text;
//get source file
string fullFileName = @"C:\Input Folder\SourceFile.txt";
DataTable dt = new DataTable();
StringBuilder sb = new StringBuilder();
//output .sql script
string sqlScript = @"C:\Output Folder\UpdateScript.SQL";
using (StreamReader sr = new StreamReader(fullFileName))
{
string firstLine = sr.ReadLine();
string[] headers = firstLine.Split(';');
//define columns for data table
foreach (string h in headers)
{
dt.Columns.Add(h);
}
int columnCount = dt.Columns.Count;
string line = sr.ReadLine();
while (line != null)
{
string[] fields = line.Split(';');
int currentLength = fields.Count();
if (currentLength < columnCount)
{
while (currentLength < columnCount)
{
line += sr.ReadLine();
currentLength = line.Split(';').Count();
}
fields = line.Split(';');
}
//load data table
dt.Rows.Add(fields);
line = sr.ReadLine();
}
foreach (DataRow dr in dt.Rows)
{
sb.AppendLine("UPDATE Contact SET " + dt.Columns[1] + " = '" + dr[1] +
"' WHERE ISNULL(" + dt.Columns[0] + ", '') = '" + dr[0] + "'");
//extra lines and GO batch separator added between UPDATE statements for formating
sb.AppendLine(Environment.NewLine);
sb.AppendLine("GO");
sb.AppendLine(Environment.NewLine);
}
//output UPDATE commands as .sql script file
File.WriteAllText(sqlScript, sb.ToString());
}
只是为了 post 我更新的代码更新,目前可以完美运行。谢谢大家的回答和帮助。
using System;
using System.IO;
using System.Text;
using System.Windows.Forms;
namespace GenererScriptSQL
{ public 部分 class Form1 : 表格 { public 表格 1() { 初始化组件(); }
private void Form1_Load(object sender, EventArgs e)
{
}
private static void AddSqlCommand(StringBuilder sql, string[] columns, string[] types, string[] values)
{
sql.AppendLine("UPDATE Contact");
sql.AppendLine("SET");
//skip LoginId columns
for (int i = 1; i < columns.Length; i++)
{
switch (types[i].Trim())
{
case "int":
sql.Append($" Contact.{columns[i].Trim()} = {values[i]}");
break;
default:
sql.Append($" Contact.{columns[i].Trim()} = '{values[i]}'");
break;
}
if (columns.Length > 1 && i != columns.Length - 1)
{
sql.Append(",");
}
sql.AppendLine();
}
sql.AppendLine();
sql.AppendLine("WHERE");
sql.AppendLine();
sql.AppendLine($" Contact.{columns[0].Trim()} = '{values[0]}'");
sql.AppendLine();
}
private static StringBuilder GenerateSqlScript(string[] fileContent)
{
var sqlCommand = new StringBuilder();
string[] types = fileContent[0].Split(';');
string[] columns = fileContent[0].Split(';');
//skip the first line(header)
for (int i = 1; i < fileContent.Length; i++)
{
string[] values = fileContent[i].Split(';');
if (values.Length >= 1)
{
AddSqlCommand(sqlCommand, columns, types, values);
}
}
return sqlCommand;
}
private void buttonCreateSqlFile_Click(object sender, EventArgs e)
{
try
{
if (IsFileSelected())
{
string[] fileContent = File.ReadAllLines(textBoxFile.Text);
if (fileContent != null)
{
StringBuilder sqlCommand = GenerateSqlScript(fileContent);
if (!string.IsNullOrWhiteSpace(sqlCommand.ToString()))
{
WriteSqlFile(sqlCommand);
}
}
}
else
{
MessageBox.Show("Sélectionner le fichier de chargement.");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void buttonSelectFile_Click(object sender, EventArgs e)
{
try
{
using (var fileBrowser = new OpenFileDialog())
{
if (fileBrowser.ShowDialog() == DialogResult.OK)
{
textBoxFile.Text = fileBrowser.FileName;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private bool IsFileSelected()
{
return !string.IsNullOrWhiteSpace(textBoxFile.Text) && File.Exists(textBoxFile.Text);
}
private void WriteSqlFile(StringBuilder sqlCommand)
{
var fileInfo = new FileInfo(textBoxFile.Text);
string BackupDate = fileInfo.Name + "_" + DateTime.Now.ToString("yyyy-MM-dd_HH-mm") + "_Update" + ".sql";
string sqlFilePath = Path.Combine(fileInfo.Directory.FullName, BackupDate);
if (File.Exists(sqlFilePath))
{
File.Delete(sqlFilePath);
}
File.WriteAllText(sqlFilePath, sqlCommand.ToString());
MessageBox.Show($@" Le fichier sql a été générée! {sqlFilePath}");
}
}
}