C# 中的 SQL Server 更新语句
Posted
技术标签:
【中文标题】C# 中的 SQL Server 更新语句【英文标题】:SQL Server Update statement in C# 【发布时间】:2021-12-03 00:51:20 【问题描述】:我有表 SelectedType
的列 type_1 ... type_2_3
的数据类型为 bit
:
P_ID type_1 type_1_1 type_1_2 type_1_3 type_2 type_2_1 type_2_2 type_2_3
1 0 1 1 0 0 1 0 1
2 1 0 1 0 0 1 0 0
3 1 0 1 0 0 1 0 0
4 0 0 0 1 1 1 1 1
...and so on
和 JSON 数组
[
"value": "type_1_1", "value": "type_2_1", "value": "type_2_3"
]
如何使用 for 循环更新 SQL Server 表,如果 "value": "type_1_1" 等于表列名 type_1_1 则将值设置为 1,或者如果值为 1 则设置为 0?
这是我目前正在尝试的:
public bool UpdatePredictSubGoalType(int id, string _selectedTypes)
string a = "[]";
string item = _selectedTypes;
if (!item.Contains('[') && !item.Contains(']'))
string c = a.Insert(1, _selectedTypes);
item = c;
bool res = false;
JArray Ja = JArray.Parse(item);
string sqlstr = "";
try
using (conn = new SqlConnection(CommonDA.GetConnectionString()))
conn.Open();
trans = conn.BeginTransaction();
try
for (int i = 0; i <= Ja.Count - 1; i++)
string x = Ja[i]["value"].ToString();
SqlCommand cmd = conn.CreateCommand();
sqlstr = @"Update SelectedType set "+ x +" = (0 or 1, i don't know how to do) where id = @id AND " + x + " = @" + x;
cmd.CommandText = sqlstr;
cmd.Transaction = trans;
cmd.Parameters.AddWithValue("@id", id);
cmd.ExecuteNonQuery();
trans.Commit();
conn.Close();
res = true;
catch (Exception Err)
trans.Rollback();
CommonLB.SystemError(Err.Message);
CommonLB.SystemError("Data", "SQL:" + sqlstr);
catch (Exception Err)
throw new ApplicationException(Err.Message, Err);
return res;
【问题讨论】:
如果我正确理解您的要求,请将值设置为1 - currentvalue
?
您从哪里获得价值? json 只有列名,但没有这些列的值
@Nonik 我假设“存在列 = 1,不存在列 = 0”
我还假设 json 包含一个我们看不到的 ID
我明白了,所以列将始终是静态的,在这种情况下,创建一个包含所有列的数组,根据缺失的列确定缺少哪些列,设置您的值
【参考方案1】:
您可以将整个 JSON 数组传递给 SQL,然后让 SQL Server 将其分解。
使用OPENJSON
显示单独的行
将其转回单行,每列有一个 1 或 0
使用ISNULL
和NULLIF
的组合来保持相同的值
如果你想覆盖所有列,那么你可以简单地做type_1 = j.type_1
UPDATE st
SET
type_1 = IIF(j.type_1 = 1, 1, st.type_1 ),
type_1_1 = IIF(j.type_1_1 = 1, 1, st.type_1_1),
type_1_2 = IIF(j.type_1_2 = 1, 1, st.type_1_2),
type_1_3 = IIF(j.type_1_3 = 1, 1, st.type_1_3),
type_2 = IIF(j.type_2 = 1, 1, st.type_2 ),
type_2_1 = IIF(j.type_2_1 = 1, 1, st.type_2_1),
type_2_2 = IIF(j.type_2_2 = 1, 1, st.type_2_2),
type_2_3 = IIF(j.type_2_3 = 1, 1, st.type_2_3)
FROM SelectedType st
CROSS APPLY (
SELECT *
FROM OPENJSON(@json)
WITH (value sysname) j
PIVOT (COUNT(value) FOR value IN
(type_1, type_1_1, type_1_2, type_1_3, type_2, type_2_1, type_2_2, type_2_3)
) pvt
) j
WHERE st.P_ID = @id;
那么你的应用代码就变得很简单了
public bool UpdatePredictSubGoalType(int id, string _selectedTypes)
if (!item.StartsWith('['))
_selectedTypes = '[' + _selectedTypes;
if (!item.EndsWith(']'))
_selectedTypes = _selectedTypes + ']';
try
const string query = @"
THE ABOVE QUERY
";
using (var conn = new SqlConnection(CommonDA.GetConnectionString()))
using (var cmd = new SqlCommand(query, conn))
cmd.Parameters.Add("@id", SqlDbType.Int).Value = id;
cmd.Parameters.Add("@json", SqlDbType.NVarChar, -1).Value = _selectedTypes;
conn.Open();
cmd.ExecuteNonQuery();
catch (Exception Err)
throw new ApplicationException(Err.Message, Err);
return true;
【讨论】:
【参考方案2】:假设我在 cmets 中提到的内容是正确的(值的存在定义为 1,缺失定义为 0)我认为,在设置 1 之前,您需要将所有内容设置为 0,或者收集你所有的列,所以 C# 可以计算出应该是 0..
类似这样的东西(安装 Dapper 以使连接上的 ExecuteAsync 成为“一件事”,或将其扩展为“长路”):
using var conn = new SqlConnection(CommonDA.GetConnectionString()));
var sql = "UPDATE t SET type_1=0, type_1_1=0, type_1_2=0, type_1_3=0, type_2=0, type_2_1=0, type_2_2=0, type_2_3=0 WHERE ID = @id";
for (int i = 0; i <= Ja.Count - 1; i++)
var c = Ja[i]["value"].ToString();
if(!Regex.IsMatch(c, @"^type_\d(_\d)?$")
continue;
sql = sql.Replace($"c=0", $"c=1");
await conn.ExecuteAsync(sql, new id );
我们首先命名表中的每一列,并将其设置为type_x_y=0
。然后对于 json 中存在的每个列名,我们将 SQL 的那部分更改为 type_x_y=1
并进行一些字符串替换
Regex 用于防止 json 供应商的 SQL 注入攻击
【讨论】:
【参考方案3】:更改你的 sql 字符串:
str = $"Update SelectedType set [x] = CASE WHEN [x] = 0 then 1 else 0 end where id = @id";
【讨论】:
以上是关于C# 中的 SQL Server 更新语句的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server参数化SQL语句中的like和in查询的语法(C#)
SQL Server参数化SQL语句中的like和in查询的语法(C#)
SQL Server参数化SQL语句中的like和in查询的语法(C#)