You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Microsoft.Data.SqlClient中实现WHERE子句匹配多个手机号的最优方案

在Microsoft.Data.SqlClient中实现WHERE子句匹配多个手机号的最优方案

嘿,兄弟,别想着用循环一个个拼条件或者重复执行查询了——不仅效率低,还容易踩SQL注入的大坑!针对MS SQL Server,我们有更优雅、安全且高效的方法来处理WHERE子句匹配多个手机号的场景,下面给你拆解几个靠谱的方案:

1. 表值参数(TVP)——最推荐的最优解

这是SQL Server和.NET配合处理多值参数的黄金方案,性能拉满还完全避免注入风险,适合批量数据场景。

步骤1:先在SQL Server中创建自定义表类型

CREATE TYPE PhoneNumberList AS TABLE (PhoneNumber VARCHAR(20))

步骤2:C#代码中构造表参数并执行查询

// 你的目标手机号列表
var phoneNumbers = new List<string> { "+7897654321", "+7878765444" };

// 构造符合自定义表类型的DataTable
var phoneTable = new DataTable();
phoneTable.Columns.Add("PhoneNumber", typeof(string));
foreach (var phone in phoneNumbers)
{
    phoneTable.Rows.Add(phone);
}

string sqlExpression = @"
select d.* from MobilePhone m
join [User] u on m.User_IDREF = u.User_ID
join Device d on u.User_ID = d.User_ID
WHERE m.MobilePhone IN (SELECT PhoneNumber FROM @PhoneNumbers);";

using (SqlConnection connection = new SqlConnection(connectionString))
{
    await connection.OpenAsync();
    using (SqlCommand command = new SqlCommand(sqlExpression, connection))
    {
        // 添加表值参数,指定类型为自定义的PhoneNumberList
        var tvpParam = command.Parameters.Add("@PhoneNumbers", SqlDbType.Structured);
        tvpParam.TypeName = "PhoneNumberList";
        tvpParam.Value = phoneTable;

        using (SqlDataReader reader = await command.ExecuteReaderAsync())
        {
            // 处理查询结果
            while (await reader.ReadAsync())
            {
                // 这里写读取数据的逻辑
            }
        }
    }
}

2. STRING_SPLIT函数——快捷轻量方案(SQL Server 2016+支持)

如果不想创建自定义表类型,用内置的STRING_SPLIT函数也能搞定,适合小批量手机号的场景。

var phoneNumbers = new List<string> { "+7897654321", "+7878765444" };
// 把手机号拼成逗号分隔的字符串
var phoneListStr = string.Join(",", phoneNumbers);

string sqlExpression = @"
select d.* from MobilePhone m
join [User] u on m.User_IDREF = u.User_ID
join Device d on u.User_ID = d.User_ID
WHERE m.MobilePhone IN (SELECT value FROM STRING_SPLIT(@PhoneNumberList, ','));";

using (SqlConnection connection = new SqlConnection(connectionString))
{
    await connection.OpenAsync();
    using (SqlCommand command = new SqlCommand(sqlExpression, connection))
    {
        command.Parameters.Add("@PhoneNumberList", SqlDbType.VarChar).Value = phoneListStr;

        using (SqlDataReader reader = await command.ExecuteReaderAsync())
        {
            // 处理结果逻辑
        }
    }
}

注意:如果手机号里可能包含逗号(虽然大概率不会),可以换个不冲突的分隔符,比如|或者;

3. 动态参数化SQL——迫不得已的备选

如果以上两种方案都没法用(比如老版本SQL Server),可以用动态生成参数的方式,绝对不要直接拼字符串! 一定要保持参数化避免注入:

var phoneNumbers = new List<string> { "+7897654321", "+7878765444" };

// 动态生成参数占位符,比如@Phone0, @Phone1...
var paramPlaceholders = new List<string>();
for (int i = 0; i < phoneNumbers.Count; i++)
{
    paramPlaceholders.Add($"@Phone{i}");
}

string sqlExpression = $@"
select d.* from MobilePhone m
join [User] u on m.User_IDREF = u.User_ID
join Device d on u.User_ID = d.User_ID
WHERE m.MobilePhone IN ({string.Join(", ", paramPlaceholders)});";

using (SqlConnection connection = new SqlConnection(connectionString))
{
    await connection.OpenAsync();
    using (SqlCommand command = new SqlCommand(sqlExpression, connection))
    {
        // 逐个添加参数
        for (int i = 0; i < phoneNumbers.Count; i++)
        {
            command.Parameters.Add($"@Phone{i}", SqlDbType.VarChar).Value = phoneNumbers[i];
        }

        using (SqlDataReader reader = await command.ExecuteReaderAsync())
        {
            // 处理结果逻辑
        }
    }
}

方案总结

  • 优先选表值参数:性能最优,支持大数据量,完全安全;
  • 小批量场景选STRING_SPLIT:无需提前创建对象,代码更简洁;
  • 动态参数化SQL仅作为最后备选,尽量少用。

备注:内容来源于stack exchange,提问作者Timur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 09:15:33