无法从非对象 Postgres json 数组中提取字段

Cannot extract field from a non-object, Postgres json array

我有一个名为 Stores 的 table,它有一个名为 store_id 的键和一个名为 Sales 的 table,其中包含一个 store_id引用和一个名为 sales_json.

的 json 字段

sales_json 看起来像这样:

[{'start_date': '2-20-15', 'end_date': '2-21-15', 'start_time': '11:00 AM', 
  'end_time': '11:00 PM', 'discount_percentage': 20}, etc] 

我有一个 plpgsql 函数,我在其中尝试确定商店当前是否有促销活动,并根据是否为真在结果 table 中存储一个名为 having_sale 的布尔值与否。

我的 SELECT 语句如下所示:

SELECT Stores.store_id,
       CASE WHEN (SELECT COUNT(*)
                  FROM (SELECT *
                        FROM json_array_elements(sales_json) AS sale
                        WHERE (now()::date BETWEEN (sale->>'start_date')::date AND
                                                   (sale->>'end_date')::date) AND
                              (now()::time BETWEEN (sale->>'start_time')::time AND
                                                   (sale->>'end_time')::time)
                       ) AS current_sales) > 0
                  THEN TRUE
            ELSE FALSE
       END) AS having_sale
FROM Stores INNER JOIN Sales
ON Stores.store_id = Sales.store_id;

代码对我来说看起来是正确的,但我收到以下错误:

psycopg2.DataError: cannot extract field from a non-object

我做错了什么,我该如何解决?

错误是由我编写的函数引起的,该函数将 json 数组附加到 sales_json。我修复了它,现在它看起来像这样:

CREATE OR REPLACE FUNCTION add_sales (insertion_id smallint, new_sales_json json)
RETURNS void AS $$
BEGIN
    UPDATE Sales
    SET sales_json = array_to_json(ARRAY(SELECT * FROM json_array_elements(sales_json)
                                         UNION ALL SELECT json_array_elements(new_sales_json)))
    WHERE store_id = insertion_id;
END;
$$ LANGUAGE plpgsql;

我之前错过了对 new_sales_json 的 json_array_elements() 调用,这就是为什么我在一个数组中获取一个数组,因此出现 cannot extract field from a non-object 错误。

除了你自己整理的,你还可以大大简化你的SELECT语句:

SELECT store_id
     , EXISTS (
          SELECT 1
          FROM   json_array_elements(s.sales_json) sale
          WHERE  now() BETWEEN (sale->>'start_date')::date + (sale->>'start_time')::time
                       AND     (sale->>'end_date')::date  + (sale->>'end_time')::time
          ) AS having_sale
FROM   Stores st
JOIN   Sales  s USING (store_id);

更短更快。
添加时间和日期会导致 timestamp [without time zone]。开始存储时间戳数据而不是日期和时间可能是个好主意。

除非,如果您的时间是指每日计划,而不是与日期相结合的绝对界限。那你一定要保持原来的表情。

最后,BETWEEN 包括两个边界,而您通常会 包括 下限,排除 上限:

WHERE now() <b>>=</b> (sale->>'start_date')::date + (sale->>'start_time')::时间
AND now() <b><</b> (sale->>'end_date')::date + (sale->>'end_time')::time

请注意,您的日期和时间是根据时区的当前设置来解释的。