在带有 IN 语句的 ORDER BY 子句中使用 CASE 对字段和顺序进行排序

Using CASE for both field and order sorting in an ORDER BY clause with IN statement

我目前在 Prisma 工作并尝试使用原始 sql 查询进行排序,但我无法实现。我正在为字段名称和排序顺序使用变量,我还想包括 IN 语句以缩短代码量(没有多个 WHEN 语句)和默认值的 ELSE 语句:

const users = await prisma.$queryRaw<User[]>(
        `
        SELECT * FROM "Users"
        ORDER BY 
            CASE WHEN  IN ('name','surname') THEN  ELSE 'id' END
            CASE WHEN  IN ('ASC','DESC') THEN  ELSE 'ASC' END
        `,
        sort?.fieldName || 'name',
        sort?.order || 'ASC'
    )

我在执行这行代码时遇到这个错误:

 "code": "P2010",
          "clientVersion": "2.17.0",
          "meta": {
            "code": "42601",
            "message": "db error: ERROR: syntax error at or near \"CASE\""
          },
          "stacktrace": [
            "Error: ",
            "Invalid `prisma.queryRaw()` invocation:",
            "",
            "",
            "  Raw query failed. Code: `42601`. Message: `db error: ERROR: syntax error at or near \"CASE\"`",
            "    at cb (/app/node_modules/@prisma/client/runtime/index.js:78689:17)",
            "    at processTicksAndRejections (internal/process/task_queues.js:93:5)"
          ],
          "message": "\nInvalid `prisma.queryRaw()` invocation:\n\n\n  Raw query failed. Code: `42601`. Message: `db error: ERROR: syntax error at or near \"CASE\"`",

我试图通过在很多变体中与逗号、括号的大量组合来实现这一点,但充其量算法只是不对记录进行排序。

我也直接在数据库上执行类似的命令(没有参数但有实际值)但结果相同。

编辑 1

我已经为测试目的准备了 SQL 查询,但没有参数(我不知道如何在原始 SQL 中使用它)。

SELECT * FROM "Users"
        ORDER BY 
            CASE WHEN 'name' IN ('name','surname') THEN 'name' ELSE 'id' END,
            CASE WHEN 'DESC' IN ('ASC','DESC') THEN 'DESC' ELSE 'ASC' END

以上代码执行正确,但排序方式仍然不正确。

您正在使用编程语言(这是 PHP 吗?)从变量创建 SQL 语句。结果 SQL 可能如下所示(如果您的变量包含单引号):

SELECT * FROM "Users"
ORDER BY 
    CASE WHEN 'name' IN ('name','surname') THEN 'name' ELSE 'id' END,
    CASE WHEN 'DESC' IN ('ASC','DESC') THEN 'DESC' ELSE 'ASC' END

... 或者像这样(如果你的变量不包含单引号):

SELECT * FROM "Users"
ORDER BY 
    CASE WHEN name IN ('name','surname') THEN name ELSE id END,
    CASE WHEN DESC IN ('ASC','DESC') THEN DESC ELSE 'ASC' END

第一个查询根本没有排序。您 select 常量字符串 'name' 和 'DESC' 的行。由于每一行的字符串都相同,因此不会进行排序。

第二次查询失败并出现错误。 ORDER BY 子句本质上变成了 ORDER BY name, DESC,但是 table 中没有列 DESC。您也不能删除逗号,因为这样您就有一个无效的 CASE 表达式。这里的主要问题是:CASE 表达式的结果不能是 SQL 关键字。

两个选项:

选项 1: 完全使用您的编程语言构建查询。大致如下:

$column = ( = "name" or  = "surname") ?  : "id";
$order = ( = "DESC") ? "DESC" : "ASC";
$query = `SELECT * FROM "Users" ORDER BY $column $order`;

选项 2: 让你的 SQL 处理这个问题:

$query = `
  SELECT * FROM "Users" 
  ORDER BY 
    CASE WHEN '' = 'DESC' THEN
      CASE WHEN '' = 'name' THEN name
           WHEN '' = 'surname' THEN surname
           ELSE id
      END
    ELSE
      ''
    END DESC,
    CASE WHEN '' <> 'DESC' THEN
      CASE WHEN '' = 'name' THEN name
           WHEN '' = 'surname' THEN surname
           ELSE id
      END
    ELSE
      ''
    END ASC
  `;

还有最后一个问题。 CASE 表达式中的结果必须是一种类型。我想 namesurname 是字符串,所以如果 id 是数字,那么你必须将它转换成字符串。例如。将 id 替换为 TO_CHAR(id, '000000000000000000').

const users = await prisma.$queryRaw<User[]>(
        `
        SELECT * FROM "Users"
        ORDER BY 
            CASE WHEN  = 'true' THEN
                CASE  WHEN 'name' THEN u.name
                WHEN 'surname' THEN u.surname
                ELSE u.id::varchar END
            END DESC,
            CASE WHEN  = 'false' THEN
                CASE  WHEN 'name' THEN u.name 
                WHEN 'surname' THEN u.surname
                ELSE u.id::varchar END
            END ASC
        `,
       sort?.order === 'DESC' ? 'true' : 'false',
       sort?.fieldName || 'id'
    )

这个查询对我有用,不幸的是我不知道如何将它与 IN 语句一起使用。 使用 u.id::varchar 因为 CASE 语句必须有一种类型 return,ID 字段是 Int,所以我将类型更改为 VARCHAR