【问题标题】:Postgres - Distinct + jsonb_object_keys gives error set-valued function called in context that cannot accept a setPostgres - Distinct + jsonb_object_keys 给出了在不能接受集合的上下文中调用的错误集合值函数
【发布时间】:2020-12-16 05:48:26
【问题描述】:

我正在尝试运行以下查询

SELECT 
DISTINCT jsonb_object_keys("classif_ai_fileregion"."defects") AS "defect_ids" 
FROM "classif_ai_fileregion" 
WHERE 
("classif_ai_fileregion"."file_id" IN 
  (SELECT U0."id" FROM "classif_ai_file" U0 ) 
AND 
"classif_ai_fileregion"."ml_model_id" IN 
  (SELECT U0."id" FROM "classif_ai_mlmodel" U0 WHERE U0."id" IN (2)))

我收到以下错误

SELECT DISTINCT jsonb_object_keys("classif_ai_fileregion"."defects") AS "defect_ids" FROM "classif_ai_fileregion" 
WHERE 
("classif_ai_fileregion"."fi...

ERROR: set-valued function called in context that cannot accept a set
  Position: 17

SELECT DISTINCT jsonb_object_keys("classif_ai_fileregion"."defects") AS "defect_ids" FROM "classif_ai_fileregion" 
                ^

现在,我尝试了上述查询的一些修改版本,它们似乎都可以工作。从上面的查询中,我将 U0."id" IN (2) 替换为 U0."id" IN (1,2)U0."id" IN (1) 并且查询有效。或者我删除 "classif_ai_fileregion"."file_id" IN (SELECT U0."id" FROM "classif_ai_file" U0 ) AND 并且它可以工作。

我无法理解为什么它适用于这些修改以及为什么它不适用于原始查询。

为便于理解查询,以下是表格。

  1. classif_ai_file

    • 身份证
  2. classif_ai_mlmodel

    • 身份证
  3. classif_ai_fileregion

    • 身份证
    • file_id
    • ml_model_id
    • 缺陷 - jsonb 类型

缺陷列的格式为 {1: {}, 2: {}}

注意:我在这一行下面写了一些类似的查询,它们可以完成一些工作,而问题中的初始查询却没有。

SELECT 
DISTINCT jsonb_object_keys("classif_ai_fileregion"."defects") AS "defect_ids" 
FROM "classif_ai_fileregion" 
WHERE 
("classif_ai_fileregion"."file_id" IN 
  (SELECT U0."id" FROM "classif_ai_file" U0 ) 
AND 
"classif_ai_fileregion"."ml_model_id" IN 
  (SELECT U0."id" FROM "classif_ai_mlmodel" U0 WHERE U0."id" IN (1)))

您可以注意到我只是在此查询中将 2 更改为 1。

SELECT 
DISTINCT jsonb_object_keys("classif_ai_fileregion"."defects") AS "defect_ids" 
FROM "classif_ai_fileregion" 
WHERE 
("classif_ai_fileregion"."file_id" IN 
  (SELECT U0."id" FROM "classif_ai_file" U0 ) 
AND 
"classif_ai_fileregion"."ml_model_id" IN 
  (SELECT U0."id" FROM "classif_ai_mlmodel" U0 WHERE U0."id" IN (1,2)))

您可以注意到我只是在此查询中将 2 更改为 1,2。

SELECT 
DISTINCT jsonb_object_keys("classif_ai_fileregion"."defects") AS "defect_ids" 
FROM "classif_ai_fileregion" 
WHERE  
"classif_ai_fileregion"."ml_model_id" IN 
  (SELECT U0."id" FROM "classif_ai_mlmodel" U0 WHERE U0."id" IN (2)))

我在这个查询中删除了一个额外的 where 子句。

SELECT 
DISTINCT jsonb_object_keys("classif_ai_fileregion"."defects") AS "defect_ids" 
FROM "classif_ai_fileregion" 
WHERE 
("classif_ai_fileregion"."file_id" IN 
  (SELECT U0."id" FROM "classif_ai_file" U0 ) 
AND 
"classif_ai_fileregion"."ml_model_id" IN 
   (2))

我只是在这里简化了 ml_model_id 的 where 子句

【问题讨论】:

  • 那么您的问题是如何避免设置返回函数的问题,或者为什么 ORM 生成的条件不能正常工作?请每个问题只问一个问题。
  • 你可以完全忽略 ORM 的事情。我想了解是什么导致我在问题中发布的查询中出现此错误。为什么它适用于我在问题底部发布的其他类似查询

标签: sql postgresql


【解决方案1】:

将函数移至 FROM 子句:

SELECT DISTINCT df.defect_id
FROM "classif_ai_fileregion" 
  cross join lateral jsonb_object_keys(classif_ai_fileregion.defects) AS df(defect_id)
WHERE ("classif_ai_fileregion"."file_id" IN (SELECT U0."id" FROM "classif_ai_file" U0 ) 
  AND "classif_ai_fileregion"."ml_model_id" IN (SELECT U0."id" 
                                                FROM "classif_ai_mlmodel" U0 
                                                WHERE U0."id" IN (2)))

请注意,您的第二个 WHERE 条件可以简化为

AND "classif_ai_fileregion"."ml_model_id" IN (2)

【讨论】:

  • 我会尝试这种方式,但由于我使用的是 Django ORM,因此构造此查询可能会很棘手。此外,我不想像你所说的那样简化最后一个条件,因为可能会添加额外的 where 子句。但是您能否帮助理解为什么它适用于 U0."id" IN (1) 而不适用于 U0."id" IN (2)?
  • 混淆层的乐趣...但是where c1 in (SELECT some_column from other_table where some_column IN (x,y,z)) 从来没有意义。并且总是等价于where c1 in (x,y,z)。如果这只适用于数据库中的某些值,那么肯定还有更多的事情发生。
  • where c1 in (SELECT some_column from other_table where some_column IN (x,y,z)) 是的,这没有意义,但where c1 in (SELECT some_column from other_table where some_column IN (x,y,z) and some_other_column IN (1,2,3)) 确实有意义。因此,我使用 django ORM 根据需要链接越来越多的 where 条件,并在此处粘贴了最简单的查询。它适用于(1)和(1,2)但不适用于(2),这非常令人困惑。另外,你能看一下我在问题中提到的类似案例吗?我觉得这是一种非常奇怪的行为。
  • 好吧,如果它适用于 (1,2) 和 (1) 但不适用于 (2) 意味着没有 id = 2 的行
  • 1 和 2 的行太多了。我手动检查了。如果我只删除 distinct 关键字,它就可以工作。在不应用 distinct 的情况下,id=2 的结果超过 8k 条记录,id=1 的结果超过 40k 条记录
【解决方案2】:

jsonb_object_keys() 返回一组记录,这意味着它返回多行。在这种情况下,SELECT 列表中不允许这样做。

在不知道您的数据的情况下,我猜您的更改以这种方式过滤了您的数据集,只剩下一条记录。当且仅当返回不超过一条记录时,SELECT 列表中才允许设置返回函数。

因此,您应该尝试将函数移入FROM 列表:

SELECT DISTINCT 
    *
FROM "classif_ai_fileregion",
    jsonb_object_keys("classif_ai_fileregion"."defects") AS "defect_ids"  
WHERE ...

逗号创建了一个CROSS JOIN LATERAL,它表示该函数会分别为每条记录调用,这应该与您最初的预期输出相同。

【讨论】:

  • 在某些情况下,SELECT 列表中允许设置返回函数。但是我也更喜欢总是把它们放在 FROM 子句中
  • @S-Man,我刚刚用更多类似的查询更新了我的问题,这些查询令人惊讶地工作。你能帮我理解其中的区别吗?感谢您提供有关 SELECT 列表接受的信息。以前不知道。
  • 这真的取决于你的数据。请在问题中添加一些最小化的数据!也许您可以创建一个小提琴:dbfiddle.uk/…
  • @S-Man,我试图在该小提琴链接中重现相同的内容,但查询工作正常。不知道为什么我们的数据库中发生错误。你可以看看小提琴看看我所做的一切
  • 你需要把你改过的小提琴的链接发给我。每次更改都会创建一个新 URL
猜你喜欢
  • 2017-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-29
  • 2017-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多