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

PostgreSQL bytea流C#合并插入/更新脚本执行报错求助

问题原因

PostgreSQL的DO匿名代码块属于PL/pgSQL执行上下文,外部传入的命名参数(如@stream)无法直接在DO块内部访问。PostgreSQL会把@stream解析成一个运算符尝试和bytea类型做运算,自然找不到匹配的运算符,因此抛出42883错误。

解决方案

针对PostgreSQL 9.4,提供两种可行的解决方式:

方式一:使用带参数传递的DO块

通过DO块的USING子句传递外部参数,在块内部使用位置参数($1、$2等)引用,同时将所有动态值改为参数化传递(避免SQL注入风险):

string upsertCommand = @"
do $$ 
begin
    UPDATE ic_plc_streams 
    SET stream = $1, mytimestamp = $2, streamlength = $3 
    WHERE plcidx = $4;
    if not found Then 
        INSERT INTO ic_plc_streams(plcidx, stream, mytimestamp, streamlength) 
        VALUES($4, $1, $2, $3);
    End if; 
end$$
using @stream, @mytimestamp, @streamlength, @plcidx;
";

using (var command = new NpgsqlCommand(upsertCommand, conn))
{
    command.Parameters.AddWithValue("@stream", NpgsqlDbType.Bytea, MyStream);
    command.Parameters.AddWithValue("@mytimestamp", DateTime.Now);
    command.Parameters.AddWithValue("@streamlength", MyStream.Length);
    command.Parameters.AddWithValue("@plcidx", PlcIdx);
    
    conn.Open();
    command.ExecuteNonQuery();
}

方式二:用C#逻辑实现UPSERT(无需DO块)

先执行UPDATE,通过返回的影响行数判断是否需要执行INSERT,这种方式更直观,也避免了PL/pgSQL的参数作用域问题:

// 先执行UPDATE
string updateCmd = @"
UPDATE ic_plc_streams 
SET stream = @stream, mytimestamp = @mytimestamp, streamlength = @streamlength 
WHERE plcidx = @plcidx;
";

using (var command = new NpgsqlCommand(updateCmd, conn))
{
    command.Parameters.AddWithValue("@stream", NpgsqlDbType.Bytea, MyStream);
    command.Parameters.AddWithValue("@mytimestamp", DateTime.Now);
    command.Parameters.AddWithValue("@streamlength", MyStream.Length);
    command.Parameters.AddWithValue("@plcidx", PlcIdx);
    
    conn.Open();
    int affectedRows = command.ExecuteNonQuery();
    
    // 如果没有更新到数据,执行INSERT
    if (affectedRows == 0)
    {
        string insertCmd = @"
        INSERT INTO ic_plc_streams(plcidx, stream, mytimestamp, streamlength) 
        VALUES(@plcidx, @stream, @mytimestamp, @streamlength);
        ";
        using (var insertCommand = new NpgsqlCommand(insertCmd, conn))
        {
            // 复用参数,或者重新添加
            insertCommand.Parameters.AddRange(command.Parameters.ToArray());
            insertCommand.ExecuteNonQuery();
        }
    }
}
额外提示
  • 永远不要直接拼接字符串生成SQL语句(比如你原来代码里的'{PlcIdx}'、'{DateTime.Now}'),这会导致SQL注入风险,所有动态值都应该通过参数传递。
  • 如果后续能升级到PostgreSQL 9.5+,可以使用更简洁的INSERT ... ON CONFLICT语法实现UPSERT,这是官方推荐的方式。

内容的提问来源于stack exchange,提问作者user1562809

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 18:23:22