如何处理在Postgres CTE(使用json_each函数)中可能为空的JSON。

huangapple go评论63阅读模式
英文:

How to handle potentially empty json in postgres CTE (with json_each function)

问题

SQL新手在这里。我正在使用Grafana和PostgreSQL构建一个可视化PoC,所以它还相当粗糙,但我想自己学习和解决问题。我正在使用一个定制的filters变量,它可以是空字符串。

我设置了一个像这样的CTE:

with filter1 as (
    select json_array_elements_text(value) from json_each('${filters}') where key = 'filter1'
)

select case when '{$filters}' != '{}'
    then sum(case when field in (select * from filter1) then 1 else 0 end)
    -- 然后...想要添加多个过滤器
    else count(*)
  end
from data;

所以过滤器可能为空,这就是错误发生的时候。我希望在case语句中调用它时CTE只会评估一次,但显然情况并非如此。

我已经注释掉了查询的不同部分,我知道当filters变量为空时错误出现在json_each函数上。错误是pq: invalid input syntax for type json

我已经测试过,当过滤器是空字符串时,该值被解释为'{}'。

我尝试过json_each(coalesce('${filters}', '{}'::json)),但似乎json_each期望非空json。

英文:

SQL newbie here. I'm using Grafana and Postgresql to build a visualization PoC, so it's pretty crude, but I want to learn and figure things out by myself. I'm using a customized filters variable, which could be empty string.

I have a CTE set up like this:

with filter1 as (
    select json_array_elements_text(value) from json_each('${filters}') where key = 'filter1'
)

select case when '{$filters}' != '{}'
    then sum(case when field in (select * from filter1) then 1 else 0 end)
    -- then ... want to add multiple filters
    else count(*)
  end
from data;

So the filters could be empty, and that's when the error happens. I was hoping that the CTE would only evaluate when it's invoked in the case statement, but apparently that's not the case.

I have commented out different parts of the query, and I know that the error is on the json_each function when the filters variable is empty. The error is pq: invalid input syntax for type json.

I have tested, so when the filters is empty string, the value is interpreted as '{}'.

I somehow tried json_each(coalesce('${filters}', '{}'::json)), but it seems like json_each is expecting non-empty json.

答案1

得分: 1

I somehow tried json_each(coalesce('${filters}', '{}'::json)), but it seems like json_each is expecting non-empty json.

There are two problems here apart from the CASE/CTE thing. Coalesce expects all of its input to be the same type, so telling it the 2nd one is json will force the 1st one to also be json, which just invokes the error you are trying to avoid. Do the casting after the coalesce, not inside of it:

coalesce('${filters}', '{}')::json

But that still won't work if ${filters} is the empty string, because coalesce doesn't consider the empty string to be the same as NULL. You can fix this with NULLIF.

coalesce(nullif('${filters}',''), '{}')::json

But once you have the NULLIF, you no longer need the coalesce, since NULL is a legal value for use with json_each, unlike the empty string.

Once you know the correct way to solve the problem, you can probably do it without the CTE.

I didn't test this exact construct, because '${filters}' is not a valid format to do parameters in PostgreSQL. That must be getting munged by the client-side library into the correct format, so I had to fake it in order to test it in psql.

英文:

> I somehow tried json_each(coalesce('${filters}', '{}'::json)), but it seems like json_each is expecting non-empty json.

There are two problems here apart from the CASE/CTE thing. Coalesce expects all of its input to be the same type, so telling it the 2nd one is json will force the 1st one to also be json, which just invokes the error you are trying to avoid. Do the casting after the coalesce, not inside of it:

coalesce('${filters}', '{}')::json

But that still won't work if ${filters} is the empty string, because coalesce doesn't consider the empty string to be the same as NULL. You can fix this with NULLIF.

coalesce(nullif('${filters}',''), '{}')::json

But once you have the NULLIF, you no longer need the coalesce, since NULL is a legal value for use with json_each, unlike the empty string.

Once you know the correct way to solve the problem, you can probably do it without the CTE.

I didn't test this exact construct, because '${filters}' is not a valid format to do parameters in PostgreSQL. That must be getting munged by the client-side library into the correct format, so I had to fake it in order to test it in psql.

huangapple
  • 本文由 发表于 2023年6月12日 21:58:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76457402.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定