SQL 在 C# 中使用字符串生成器查询

SQL Query with String Builder in C#

我是 C# 的新手,当我尝试使用 stringbuilder 执行 sql 查询时,我 运行 遇到了一些问题。

这是 table 的一部分,命名为:

| ID   | Name      | InternalID |
|:----:|:---------:| :---------:|
| 1    | Emory Lu  | 84765      |
| ...  | ...       | ...        |
| 8    | John Smith| 52455      |
| 9    | John smith| 49         |
| ...  | ...       | ...        |

请注意,在此 table 中,John Smith 被分配了两个不同的 InternalID(字符串类型)。在第二条记录中,他的姓氏以小写“s”开头。

我在输入员工姓名时对 select 员工的 InternalID(字符串类型)执行了一个简单的 sql 查询:

public DataTable findInternalID(string name)
{
    RecordConnection.Open();
    DataTable output = new DataTable();
    OleDbCommand bdCommand = RecordConnection.CreateCommand() as OleDbCommand;
    StringBuilder x = new StringBuilder();

    // SELECT InternalID FROM EmployeeList WHERE Name = "(name)"
    x.AppendLine("SELECT InternalID ");
    x.AppendLine("FROM EmployeeList ");
    x.AppendLine($"WHERE Name LIKE '%{name}%'");

    bdCommand.CommandText = x.ToString();
    _dataAdapter = new OleDbDataAdapter(bdCommand);
    _dataAdapter.Fill(output);

    RecordConnection.Close();
    return output;

}

这段代码适用于只有一条记录的员工,但对于有多条记录的员工,它会同时填充所有 InternalID 记录和输出,因为这一行:

x.AppendLine($"WHERE Name LIKE '%{name}%'");

所以我尝试将LIKE关键字改成“=”:

x.AppendLine($"WHERE Name = '%{name}%'");

但这给了我一个错误。

如何编辑我的代码,以便在输入“John Smith”时仅输出“52455”而输入“John smith”仅输出“49”。

在main函数下,我写了一段代码来测试这个功能:

  string name = "John Smith"; // or John smith
  DataTable output = _accessManager.findInternalID(name);
         
  String message = result.Rows[0][0].ToString(); // Or ROWS[1][0]
  MessageBox.Show(message);

顺便说一句,我用的是 MS Access :)

=================问题解决了! ====================

非常感谢大家帮助我。我考虑了大家的建议,这是我的最终代码。我使用了 StrComp() 功能,该功能非常适合在 MS Access 中执行区分大小写的 sql 查询:

public DataTable findInternalID(string name)
        {
            RecordConnection.Open();
            DataTable output = new DataTable();
            OleDbCommand bdCommand = RecordConnection.CreateCommand() as OleDbCommand;

            StringBuilder x = new StringBuilder();
            x.AppendLine("SELECT InternalID ");
            x.AppendLine("FROM EmployeeList ");
            x.AppendLine($"WHERE StrComp(Name, @name, 0) = 0;");

            bdCommand.CommandText = x.ToString();
            bdCommand.Parameters.AddWithValue("name", $"{name}");

            _dataAdapter = new OleDbDataAdapter(bdCommand);
            _dataAdapter.Fill(output);

            RecordConnection.Close();
            return output;
        }

仅供将来参考的一些注意事项,如果您使用的是 MS Access,则 COLLATEvarbinary(MAX) 不适合您。

在SQL服务器中你只需要case-sensitive搜索,试试这个!

x.AppendLine($"WHERE Name = '{name}' COLLATE Latin1_General_CS_AS ");

在MS-Access,试试这个!

x.AppendLine($"WHERE StrComp(Name, '{name}', 0) = 0");

对于初学者,您永远不应该通过将用户提供的数据连接到查询字符串中来构建 SQL 查询。这样做会使您容易受到 SQL Injection 的攻击。相反,您应该使用查询参数将用户提供的数据传递给您的查询。

重写原始函数以使用参数可能如下所示:

public DataTable findInternalID(string name)
{
    RecordConnection.Open();
    var output = new DataTable();
    var bdCommand = RecordConnection.CreateCommand() as OleDbCommand;
    var x = new StringBuilder();

    // SELECT InternalID FROM EmployeeList WHERE Name = "(name)"
    x.AppendLine("SELECT InternalID ");
    x.AppendLine("FROM EmployeeList ");
    x.AppendLine("WHERE Name LIKE @name");

    bdCommand.CommandText = x.ToString();
    bdCommand.Parameters.AddWithValue("name", $"%{name}%");
    _dataAdapter = new OleDbDataAdapter(bdCommand);
    _dataAdapter.Fill(output);

    RecordConnection.Close();
    return output;
}

至于区分大小写的查询,我不能说我真的做到了。看起来 COLLATE 应该可以工作,假设您的数据库是 SQL 服务器。

x.AppendLine("SELECT InternalID ");
x.AppendLine("FROM EmployeeList ");
x.AppendLine("WHERE Name = @name COLLATE Latin1_General_CP1_CS_AS");

或者,也许转换为 varbinary(MAX) 来比较字节?

x.AppendLine("SELECT InternalID ");
x.AppendLine("FROM EmployeeList ");
x.AppendLine("WHERE CAST(Name as varbinary(MAX)) = CAST(@name AS varbinary(MAX))");

此外,最后一点,您根本不需要使用 StringBuilder。如果您想跨多行格式化语句,您可以只使用带有 @ 标识符的逐字 string

string commandText = @"SELECT InternalId
FROM EmployeeList
WHERE Name = @name COLLATE Latin1_General_CP1_CS_AS";