2016-01-13 121 views
1

我正在学习如何在PostgreSQL中处理JSON。使用PostgreSQL在JSON中处理null或缺少的属性

我有一个表,有一些列。一列是JSON字段。该列中的数据至少有以下三种变体:

Case 1: {"createDate": 1448067864151, "name": "world"} 
Case 2: {"createDate": "", "name": "hello"} 
Case 3: {"name": "sky"} 

稍后,我想选择createDate。

TO_TIMESTAMP((attributes->>'createDate')::bigint * 0.001) 

对于情况1,当数据存在并且可以转换为bigint时,它工作正常。 但是什么时候不是?我该如何处理?

I read this article。它解释了我们可以添加检查约束来执行一些基本验证。或者,我可以在插入数据之前进行模式验证(在客户端)。这两种想法都有优点和缺点。

使用检查约束

CONSTRAINT validate_createDate CHECK ((attributes->>'createDate')::bigint >= 1) 

这迫使非空的字段(案例3失败)。但我希望该属性是可选的。此外,如果该属性由于为空而不能转换为bigint(情况2),则会出错。

在客户端使用JSON模式验证插入之前

这工作,部分是因为该架构验证确保了进来符合该模式的数据。就我而言,我可以控制哪些客户端访问这个表,所以这没问题。但是后面的SQL无关紧要,因为我的验证器会让所有三种情况都通过。

回答

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) 
0

大厦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)