SQL Server SQL插入不考虑在C#代码中插入空值

yftpprvb  于 2022-11-21  发布在  C#
关注(0)|答案(3)|浏览(145)

我 有 一 段 很 好 的 C # 代码 , 它 允许 我 将 数据 导入 到 一 个 列 数 比 SQL 表 少 的 表 中 ( 因为 文件 格式 一直 不 好 ) 。
当 我 在 列 中 有 一 个 空 条目 时 , 我 的 问题 就 出现 了 。 values 语句 没有 从 csv 中 获取 空 列 , 所以 我 收到 了 错误
插入 列 多于 值
下面 是 打印 到 消息 框 的 查询 ...

如 您 所 见 , 4 至 11 号 机组 成员 没有 任何 内容 , 以下 是 文件 ...

请 看 我 的 代码 :

SqlConnection ADO_DB_Connection = new SqlConnection();
ADO_DB_Connection = (SqlConnection)
(Dts.Connections["ADO_DB_Connection"].AcquireConnection(Dts.Transaction) as SqlConnection);

// Inserting data of file into table
int counter = 0;
string line;
string ColumnList = "";

// MessageBox.Show(fileName);

System.IO.StreamReader SourceFile =
new System.IO.StreamReader(fileName);

while ((line = SourceFile.ReadLine()) != null)
{
    if (counter == 0)
    {
        ColumnList = "[" + line.Replace(FileDelimiter, "],[") + "]";
    }
    else
    {
        string query = "Insert into " + TableName + " (" + ColumnList + ") ";
        query += "VALUES('" + line.Replace(FileDelimiter, "','") + "')";

        // MessageBox.Show(query.ToString());

        SqlCommand myCommand1 = new SqlCommand(query, ADO_DB_Connection);
        myCommand1.ExecuteNonQuery();
    }

    counter++;
}

中 的 每 一 个
如果 你 能 建议 如何 在 插入 中 包括 那些 字段 , 那 就 太 好 了 。
这里 是 相同 的 文件 , 但 用 文本 编辑 器 打开 , 并 没有 以 图片 格式 给出 . . .

Date,Flight_Number,Origin,Destination,STD_Local,STA_Local,STD_UTC,STA_UTC,BLOC,AC_Reg,AC_Type,AdultsPAX,ChildrenPAX,InfantsPAX,TotalPAX,AOC,Crew 1,Crew 2,Crew 3,Crew 4,Crew 5,Crew 6,Crew 7,Crew 8,Crew 9,Crew 10,Crew 11
05/11/2022,241,BOG,SCL,15:34,22:47,20:34,02:47,06:13,N726AV,"AIRBUS A-319                  ",0,0,0,36,AV,100612,161910,323227

格式

emeijp43

emeijp431#

不触及SQL注入的可能性,因为我自由处理此代码。如果这是系统生成的文件(大型机提取,从动态或LoB应用程序转储),SQL注入的可能性非常低。

// Char required
char FileDelimiterChar = FileDelimiter.ToChar()[0];
int columnCount = 0;
while ((line = SourceFile.ReadLine()) != null)
{
    if (counter == 0)
    {
        ColumnList = "[" + line.Replace(FileDelimiterChar, "],[") + "]";
        // How many columns in line 1. Assumes no embedded commas
        // The following assumes FileDelimiter is of type char
        // Add 1 as we will have one fewer delimiters than columns
        columnCount = line.Count(x => x == FileDelimiterChar) +1;
    }
    else
    {
        string query = "Insert into " + TableName + " (" + ColumnList + ") ";
        // HACK: this fails if there are embedded delimiters
        int foundDelimiters = line.Count(x => x == FileDelimiter) +1;
        // at this point, we know how many delimiters we have
        // and how many we should have.
        string csv = line.Replace(FileDelimiterChar, "','");

        // Pad out the current line with empty strings aka ','
        // Note: I may be off by one here
        // Probably a classier linq way of doing this or string.Concat approach
        for (int index = foundDelimiters; index <= columnCount; index++)
        {
             csv += "','";
        }

        query += "VALUES('" + csv + "')";

        // MessageBox.Show(query.ToString());

        SqlCommand myCommand1 = new SqlCommand(query, ADO_DB_Connection);
        myCommand1.ExecuteNonQuery();
    }

    counter++;
}

类似的东西应该会让你朝着正确的方向前进。概念是你需要检查第一行,看看你 * 应该 * 有多少列。然后对于每一行数据,你 * 实际 * 有多少列,然后在空字符串中存根。
如果您将其更改为使用SqlCommand对象和参数,则近似逻辑仍然相同。您将通过计算第一行中的列来添加所有期望的参数,然后为每一行添加值,如果行较短,则只需发送空字符串(或dbnull或系统期望的任何内容)。
IMO最大的收获是CSV解析库的存在是有原因的,而且上面的伪代码中有太多的情况没有解决,您可能会想放弃当前的方法,转而使用标准解析库,然后在使用它的同时,解决潜在的安全缺陷。
我看到了您更新的注解,您将把格式问题带回给源方。如果他们不能解决这些问题,我将设想您的SSIS包
脚本任务-〉数据流任务。
指令码工作会将不受控制的数据转换成数据流程工作可以行程的严格CSV方言。请将数据预先行程成新档案,而不是尝试修改现有的档案。
然后,数据流成为平面文件源-〉OLEDB目标的一个片段

14ifxucb

14ifxucb2#

下面是处理这个文件的方法......不过我还是会要求使用Json或XML。
你需要设置两个输出。航班信息(前16列)和航班机组(业务键[航班号和日期可能]和机组ID)。
在我看来,问题是如何在CSV中处理机组人员。
基本步骤是读取文件,用正则表达式拆分文件,把前16列写到output1,剩下的(用key)写给机组人员。

var lines = System.File.IO.ReadAllLines("filepath");
for(int i =1; i<lines.length; i++)
{
    var = new System.Text.RegularExpressions.Regex("new Regex("(?:^|,)(?=[^\"]|(\")?)\"?((?(1)(?:[^\"]|\"\")*|[^,\"]*))\"?(?=,|$)"); //Some code I stole to split quoted CSVs
    var m = r.Matches(line[i]); //Gives you all matches in a MatchCollection
    //first 16 columns are always correct
    OutputBuffer0.AddRow();
    OutputBuffer0.Date = m[0].Groups[2].Value;
    OutputBuffer0.FlightNumber = m[1].Groups[2].Value;
    [And so on until m[15]]
    for(int j=16; j<m.Length; j++)
    {
         OutputBuffer1.AddRow(); //This is a new output that you need to set up
         OutputBuffer1.FlightNumber = m[1].Groups[2].Value;
         [Keep adding to make a business key here]
         OutputBuffer1.CrewID = m[j].Groups[2].Value;
    }
}

注意,我只是输入了所有这些内容,给予你一个没有任何测试的总体计划。例如,m[0]可能实际上是m[0]。值和所有数据类型将是需要转换的字符串。
要查看regex是如何处理行的,请访问https://regex101.com/r/y8Ayag/1以获得解释。您甚至可以粘贴行数据。

**UPDATE:**我刚刚测试过这个,现在它可以工作了。需要转义regex函数。并指定你想要组2的值。还需要在File.ReadAllLines中命中IO。

suzh9iv8

suzh9iv83#

我最终实现的解决方案完全避免了脚本任务。也意味着没有SQL注入的可能性。
我做了一个平面文件导入。所有的内容都被导入到一个列中,然后在SQL中使用split_string和一个透视,然后在整理和关闭到main之前插入到一个临时表中。
平面文件导入到单列表-〉SQL转换-〉加载
这也允许我使用foreach循环容器更好地迭代文件。
ELT在这个场合。
感谢所有的帮助和指导。

相关问题