在 WHERE IN 子句中使用 JSONB 数组中的值

Posted

技术标签:

【中文标题】在 WHERE IN 子句中使用 JSONB 数组中的值【英文标题】:Use Values from JSONB Array inside a WHERE IN Clause 【发布时间】:2016-07-03 23:52:36 【问题描述】:

我在 PostgreSQL 中有一个 JSONB 对象:

'"cars": ["bmw", "mercedes", "pinto"], "user_name": "ed"'

我正在尝试在 SELECTWHERE 子句中使用其中的“汽车”数组中的

SELECT car_id FROM cars WHERE car_type IN ('bmw', 'mercedes', 'pinto');

这将正确返回值 1、2 和 3 - 请参阅本文底部的表格设置。

目前,在我的功能中,我这样做:

(1) Extract the "cars" array into a variable `v_car_results`.
(2) Use that variable in the `WHERE` clause.

Pseudo code:

    DECLARE v_car_results TEXT
    BEGIN
        v_car_results = '"cars": ["bmw", "mercedes", "pinto"], "user_name": "ed"'::json#>>'cars';
            -- this returns 'bmw', 'mercedes', 'pinto'
        SELECT car_id FROM cars WHERE car_type IN ( v_car_results );
    END

但是,SELECT 语句没有返回任何行。我知道它将这 3 种汽车类型读取为 single 类型。 (如果我在“汽车”元素中只包含一个car_type,则查询工作正常。)

如何将这些值视为WHERE 子句中的数组

我尝试了其他一些方法:

    ANY 子句。

    投射的各种尝试。

    这些查询:

    SELECT car_id FROM cars
    WHERE car_type IN (json_array_elements_text('["bmw", "mercedes", "pinto"]'));
    
    ...
    WHERE car_type IN ('"cars": ["bmw", "mercedes", "pinto"], "user_name": "ed"':json->>'cars');
    

感觉就像我错过了一些简单的东西。但我已经掉进了这个兔子洞。 (也许我什至不应该使用::json#>> 运算符?)

表设置

CREATE TABLE cars (
   car_id SMALLINT
 , car_type VARCHAR(255)
);

INSERT INTO cars (car_id, car_type)
VALUES
  (1, 'bmw')
, (2, 'mercedes')
, (3, 'pinto')
, (4, 'corolla');

SELECT car_id FROM cars
WHERE car_type IN ('bmw', 'mercedes', 'pinto'); -- Returns Values : 1, 2, 3

【问题讨论】:

【参考方案1】:

假设当前的 Postgres 版本为 9.5,因为它没有被指定。

使用集合返回函数jsonb_array_elements_text()(作为表函数!)并加入到结果:

SELECT c.car_id
FROM   jsonb_array_elements_text('"cars": ["bmw", "mercedes", "pinto"]
                                 , "user_name": "ed"'::jsonb->'cars') t(car_type)
JOIN   cars c USING (car_type);

从带有jsonb->'cars' 的对象中提取JSON 数组,并将生成的JSON 数组(仍然是数据类型jsonb)传递给函数。 (运营商#> 也可以完成这项工作。)

旁白:::json#>> 不仅仅是一个操作员。它是对 json (::json) 的强制转换,然后是运算符 #>>。你也不需要。

生成的类型text 很方便地匹配您的列类型varchar(255),因此我们不需要类型转换。并分配列名car_type 以允许在连接条件中使用USING 的语法简写。

IN ()= ANY() 的替代方法相比,这种形式更短、更优雅并且通常更快——这也可以。您的尝试非常接近,但您需要带有 子查询 的变体。这会起作用:

SELECT car_id FROM cars
WHERE  car_type IN (SELECT json_array_elements_text('["bmw", "mercedes", "pinto"]'));

或者,更清洁:

SELECT car_id FROM cars
WHERE  car_type IN (SELECT * FROM json_array_elements_text('["bmw", "mercedes", "pinto"]'));

详细解释:

How to use ANY instead of IN in a WHERE clause with Rails?

相关:

How to turn json array into postgres array?

【讨论】:

像魅力一样工作!非常感谢!那绝对是我的一天! :-) 你现在呢?我没有看到您更新的解决方案。这绝对看起来更干净。我会和那个一起去的! Erwin 您似乎是一位乐于助人的专家,可以解决我见过的大多数问题中的 postgresql 查询。你知道这个问题的sql查询有什么问题吗:***.com/questions/38679190/…

以上是关于在 WHERE IN 子句中使用 JSONB 数组中的值的主要内容,如果未能解决你的问题,请参考以下文章

从带有 WHERE 子句的 JSONB 字段中选择

在 Postgresql 和 IN 子句中索引 jsonb 列

用于嵌套 jsonb 的雄辩的 Where 子句。 PostgreSQL

在 mysql where in 子句中对数组使用 implode

将 IN() 用于数组的 PL/SQL where 子句

将数组转换为 WHERE IN mysql 子句的格式