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

Prisma含IN的原生SQL参数化查询报错,求正确实现方式

Prisma原生SQL参数化查询IN条件的正确实现

Prisma原生SQL完全支持参数化查询,你遇到的42601语法错误(PostgreSQL语法错误),核心原因是IN子句的数组参数没有正确展开为多个占位符——Prisma不会自动把数组参数拆分成IN ($2, $3)这种格式,直接传数组会被当作单个参数,导致SQL语法错误。

正确实现步骤

下面以你的getWarmTransferStatusReport解析器为例,给出完整的参数化实现方案:

  1. 预处理过滤参数与占位符
    先把status、userEmail这类IN条件的数组参数,转换成对应的占位符列表和扁平化的参数数组,避免SQL注入同时解决语法问题:
import { Prisma } from '@prisma/client';

export async function getWarmTransferStatusReport(parent, args, context) {
  const { page = 1, pageSize = 10, sortBy = 'createdAt', sortDir = 'ASC', status = [], userEmail = [] } = args;
  const params: any[] = [];
  const whereClauses: string[] = [];
  let paramIndex = 1;

  // 处理status IN条件
  if (status.length > 0) {
    const placeholders = status.map(() => `$${paramIndex++}`).join(', ');
    whereClauses.push(`status IN (${placeholders})`);
    params.push(...status);
  }

  // 处理userEmail IN条件
  if (userEmail.length > 0) {
    const placeholders = userEmail.map(() => `$${paramIndex++}`).join(', ');
    whereClauses.push(`user_email IN (${placeholders})`);
    params.push(...userEmail);
  }

  // 处理分页
  const offset = (page - 1) * pageSize;
  params.push(pageSize, offset);
  const limitPlaceholder = `$${paramIndex++}`;
  const offsetPlaceholder = `$${paramIndex}`;

  // 处理排序(限制合法字段,防止SQL注入)
  const allowedSortFields = ['createdAt', 'status', 'user_email'];
  const safeSortBy = allowedSortFields.includes(sortBy) ? sortBy : 'createdAt';
  const safeSortDir = ['ASC', 'DESC'].includes(sortDir.toUpperCase()) ? sortDir.toUpperCase() : 'ASC';

  // 构建完整SQL
  const whereClause = whereClauses.length > 0 ? `WHERE ${whereClauses.join(' AND ')}` : '';
  const sql = `
    SELECT id, status, user_email, created_at, updated_at
    FROM warm_transfers
    ${whereClause}
    ORDER BY ${safeSortBy} ${safeSortDir}
    LIMIT ${limitPlaceholder} OFFSET ${offsetPlaceholder}
  `;

  // 执行参数化查询
  const results = await context.prisma.$queryRaw(Prisma.sql`${sql}`, ...params);
  return results;
}
  1. 使用Prisma.join简化占位符生成
    如果你想用Prisma.join工具,可以把占位符生成逻辑替换为:
// 处理status IN条件
if (status.length > 0) {
  const placeholders = Prisma.join(status.map((_, idx) => Prisma.raw(`$${paramIndex + idx}`)));
  whereClauses.push(`status IN (${placeholders})`);
  params.push(...status);
  paramIndex += status.length;
}

本质和手动生成占位符一致,只是用Prisma的工具类来拼接。

期望生成的最终SQL示例

当传入status: ['PENDING', 'COMPLETED']、userEmail: ['user1@example.com']、page=1、pageSize=10时,最终执行的参数化SQL会是:

SELECT id, status, user_email, created_at, updated_at
FROM warm_transfers
WHERE status IN ($1, $2) AND user_email IN ($3)
ORDER BY createdAt ASC
LIMIT $4 OFFSET $5

对应的参数数组为:['PENDING', 'COMPLETED', 'user1@example.com', 10, 0]

关键注意事项

  • 禁止直接拼接用户输入:所有用户传入的参数(包括排序字段、过滤值)都必须通过参数化传递,或者做合法性校验(如排序字段限制在允许列表内),防止SQL注入。
  • 参数顺序必须严格对应:占位符的编号$1、$2要和params数组的顺序完全一致,否则会出现参数不匹配的错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 21:51:15