我正在学习如何在PostgreSQL中处理JSON。
我有一些包含一些列的表。一列是JSON字段。该列中的数据至少包含以下三种变体:
Case 1: {"createDate": 1448067864151, "name": "world"}
Case 2: {"createDate": "", "name": "hello"}
Case 3: {"name": "sky"}
稍后,我想选择createDate。
TO_TIMESTAMP((attributes->>'createDate')::bigint * 0.001)
当数据存在且可转换为bigint时,对于案例1可以正常工作。 但是什么时候不是呢?我该如何处理?
I read this article。它解释了我们可以添加检查约束来执行一些基本验证。或者,我可以在插入数据之前(在客户端)进行模式验证。这两种想法都有利有弊。
使用检查约束
CONSTRAINT validate_createDate CHECK ((attributes->>'createDate')::bigint >= 1)
这会强制一个不可为空的字段(情况3失败)。但我希望该属性是可选的。此外,如果属性没有转换为bigint,因为它是空白的(案例2),则会出错。
在插入
之前在客户端使用JSON模式验证这部分地起作用,因为模式验证确保了哪些数据符合模式。在我的情况下,我可以控制哪些客户端访问此表,所以这没关系。但是,由于我的验证器将允许通过所有三种情况,因此对SQL不重要。
答案 0 :(得分:1)
基本上,您需要检查createDate
属性是否为空:
WITH data(attributes) AS ( VALUES
('{"createDate": 1448067864151, "name": "world"}'::JSON),
('{"createDate": "", "name": "hello"}'::JSON),
('{"name": "sky"}'::JSON)
)
SELECT to_timestamp((attributes->>'createDate')::bigint * 0.001) FROM data
WHERE
(attributes->>'createDate') IS NOT NULL
AND
(attributes->>'createDate') != '';
输出:
to_timestamp
----------------------------
2015-11-20 17:04:24.151-08
(1 row)
答案 1 :(得分:1)
在Dmitry's answer上构建,您还可以使用json_typeof函数检查json类型。注意json运算符: - >得到json而不是 - >>始终将值转换为字符串的运算符。
通过使用CASE条件而不是WHERE子句检查SELECT,我们还保留没有createdDate的行。根据您的使用情况,这可能会更好。
WITH data(attributes) AS ( VALUES
('{"createDate": 1448067864151, "name": "world"}'::JSON),
('{"createDate": "", "name": "hello"}'::JSON),
('{"name": "sky"}'::JSON)
)
SELECT
CASE WHEN (json_typeof(attributes->'createDate') = 'number')
THEN to_timestamp((attributes->>'createDate')::bigint * 0.001)
END AS created_date
FROM data
;
输出:
created_date
----------------------------
"2015-11-21 02:04:24.151+01"
""
""
(3 rows)