【问题标题】:PostgreSQL - could not identify an equality operator for type jsonPostgreSQL - 无法识别 json 类型的相等运算符
【发布时间】:2018-01-24 10:40:44
【问题描述】:

我有以下疑问:

SELECT 
  distinct(date(survey_results.created_at)), 
  json_build_object(
    'high', 
    ROUND( 
      COUNT(*) FILTER (WHERE ( scores#>>'{medic,categories,motivation}' in('high', 'medium'))) OVER(order by date(survey_results.created_at) ) * 1.0 / 
      (
        CASE (COUNT(*) FILTER (WHERE (scores#>>'{medic,categories,motivation}' in('high','medium','low'))) OVER(order by date(survey_results.created_at))) 
        WHEN 0.0 THEN 1.0 
        ELSE (COUNT(*) FILTER (WHERE (scores#>>'{medic,categories,motivation}' in('high','medium','low'))) OVER(order by date(survey_results.created_at))) 
        END)* 100, 2 ) ) AS childcare FROM survey_results GROUP BY date, scores ORDER BY date asc; 

问题在于使用distinct(date(survey_results.created_at))。就地查询返回错误:

could not identify an equality operator for type json

这是显示该问题的 db fiddle:

https://www.db-fiddle.com/f/vUBjUyKDUNLWzySHKCKcXA/1

我该如何解决这个问题?

【问题讨论】:

  • distinctNOT 一个函数。它始终适用于结果的 所有 列。 distinct(a),bdistinct a, (b)distinct a, b 相同。正因为如此,distinct 尝试比较您的第二列的相同值,该列的类型为json,并且无法与= 进行比较
  • 知道了,这个查询返回了一个重复的日期,我怎样才能在不使用 distinct 的情况下修复它?

标签: sql json postgresql


【解决方案1】:

使用jsonb_build_object。注意bjson 之后的二进制文件。

【讨论】:

  • to_jsonb 帮助了我。重要的是 jsonb 类型确实有一个相等运算符。
  • 我试图用 JSON 创建一个 UNION 并收到此消息。我从 JSON 切换到 JSONB 并且效果很好。谢谢。
  • 我在尝试将 json_build_array() 与另一个 json_build_array() 合并时发现了一个类似的错误,但发现它不起作用,然后我发现了一个类似的解决方案,切换到 jsonb 函数或转换为 jsonb。我很好奇为什么没有操作员。
  • 运行此查询后我现在明白了。对 json 来说相等意味着什么是值得怀疑的。 SELECT LENGTH('{"a":1,"a":2}'::json::text), LENGTH('{"a":1,"a":2}'::jsonb::text), LENGTH('{ "a":1}'::json::text), LENGTH('{ "a":1}'::jsonb::text) 此处显示了类似的比较:stackoverflow.com/a/33731703/5078765
【解决方案2】:

问题在于使用distinct(date(survey_results.created_at))

没有。问题在于使用 DISTINCT - 那是 不是 一个函数。它始终适用于to all columns of the resultdistinct(a), bdistinct a, (b)distinct a, b 相同。正因为如此, distinct 尝试比较您的第二列的相同值,该列是 json 类型,无法与 =

进行比较

如果您只想要“最新”值,您可以使用 Postgres 的 distinct on () 运算符:

SELECT distinct on (date(survey_results.created_at)) 
       date(survey_results.created_at) as date,
       json_build_object('high', 
        ROUND( 
      COUNT(*) FILTER (WHERE ( scores#>>'{medic,categories,motivation}' in('high', 'medium'))) OVER(order by date(survey_results.created_at) ) * 1.0 / 
      (
        CASE (COUNT(*) FILTER (WHERE (scores#>>'{medic,categories,motivation}' in('high','medium','low'))) OVER(order by date(survey_results.created_at))) 
        WHEN 0.0 THEN 1.0 
        ELSE (COUNT(*) FILTER (WHERE (scores#>>'{medic,categories,motivation}' in('high','medium','low'))) OVER(order by date(survey_results.created_at))) 
        END)* 100, 2 ) ) AS childcare 
FROM survey_results 
GROUP BY date, scores 
ORDER BY date asc; 

distinct on ()order by 结合使用为ON () 部分中指定的列的后续相同值选择第一行。在这种情况下,它将返回最早的日期。如果您想要“最新”行,请将排序顺序更改为desc

https://www.db-fiddle.com/f/vUBjUyKDUNLWzySHKCKcXA/1

【讨论】:

  • 我们不能按日期分组吗(suryve_results.created_at)? @a_horse_with_no_name
【解决方案3】:

迁移到使用 JSONB 就不会出现这个问题了。

这是几年前 Postgres 9.4 发布时遵循的标准建议。这是 Ruby on Rails 社区中的一个线程,描述了迁移到 JSONB 作为解决方案。

这里是线程:https://github.com/rails/rails/issues/17706

【讨论】:

    猜你喜欢
    • 2014-04-30
    • 1970-01-01
    • 2017-09-28
    • 1970-01-01
    • 2013-10-07
    • 2021-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多