2016-02-27 98 views
3

在线扑克玩家可以有选择地申购获得使用JSONB_ARRAY_ELEMENTS到游戏室1或2的游戏室与WHERE ... IN条件

而且他们可以暂时禁止作弊。

CREATE TABLE users (
     uid SERIAL PRIMARY KEY, 

     paid1_until timestamptz NULL,  -- may play in room 1 
     paid2_until timestamptz NULL,  -- may play in room 2 

     banned_until timestamptz NULL, -- punished for cheating etc. 
     banned_reason varchar(255) NULL 
); 

这里上表中充满了4个测试记录:

INSERT INTO users (paid1_until, paid2_until, banned_until, banned_reason) 
VALUES (NULL, NULL, NULL, NULL), 
     (current_timestamp + interval '1 month', NULL, NULL, NULL), 
     (current_timestamp + interval '2 month', current_timestamp + interval '4 month', NULL, NULL), 
     (NULL, current_timestamp + interval '8 month', NULL, NULL); 

所有4条属于同一个人 - 谁已经通过不同的社交网络身份验证自己(例如通过Facebook,Twitter,苹果游戏中心等)

我试图创建一个存储功能,这将需要数字用户ID列表(以JSON阵列)和合并记录属于同一个人为一个记录 - withou牛逼失去她支付或处罚:

CREATE OR REPLACE FUNCTION merge_users(
     IN in_users jsonb, 
     OUT out_uid integer) 
     RETURNS integer AS 
$func$ 
DECLARE 
     new_paid1 timestamptz; 
     new_paid2 timestamptz; 
     new_banned timestamptz; 
     new_reason varchar(255); 
BEGIN 
     SELECT min(uid), 
       current_timestamp + sum(paid1_until - current_timestamp), 
       current_timestamp + sum(paid2_until - current_timestamp), 
       max(banned_until) 
     INTO 
       out_uid, new_paid1, new_paid2, new_banned 
     FROM users 
     WHERE uid IN (SELECT JSONB_ARRAY_ELEMENTS(in_users)); 

     IF out_uid IS NOT NULL THEN 
       SELECT banned_reason 
       INTO new_reason 
       FROM users 
       WHERE new_banned IS NOT NULL 
       AND banned_until = new_banned 
       LIMIT 1; 

       DELETE FROM users 
       WHERE uid IN (SELECT JSONB_ARRAY_ELEMENTS(in_users)) 
       AND uid <> out_uid; 

       UPDATE users 
       SET paid1_until = new_paid1, 
        paid2_until = new_paid2, 
        banned_until = new_banned, 
        banned_reason = new_reason 
       WHERE uid = out_uid; 
     END IF; 
END 
$func$ LANGUAGE plpgsql; 

不幸的是,它的使用会导致以下错误:

# TABLE users; 
uid |   paid1_until   |   paid2_until   | banned_until | banned_reason 
-----+-------------------------------+-------------------------------+--------------+--------------- 
    1 |        |        |    | 
    2 | 2016-03-27 19:47:55.876272+02 |        |    | 
    3 | 2016-04-27 19:47:55.876272+02 | 2016-06-27 19:47:55.876272+02 |    | 
    4 |        | 2016-10-27 19:47:55.876272+02 |    | 
(4 rows) 

# select merge_users('[1,2,3,4]'::jsonb); 
ERROR: operator does not exist: integer = jsonb 
LINE 6:   WHERE uid IN (SELECT JSONB_ARRAY_ELEMENTS(in_users)) 
         ^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts. 
QUERY: SELECT min(uid), 
       current_timestamp + sum(paid1_until - current_timestamp), 
       current_timestamp + sum(paid2_until - current_timestamp), 
       max(banned_until) 
                       FROM users 
     WHERE uid IN (SELECT JSONB_ARRAY_ELEMENTS(in_users)) 
CONTEXT: PL/pgSQL function merge_users(jsonb) line 8 at SQL statement 

请帮我解决这个问题。

这里是a gist with SQL code为了您的方便。

+0

为什么要使用'jsonb'数组有什么特定的原因?为什么不使用int []'数组? – Patrick

+0

是的,我想使用JSON,因为这是我的移动应用程序如何与PHP + PostrgreSQL后端对话。我确定我的问题可以通过JSON解决,我只是缺少一些。次要。 –

回答

3

jsonb_array_elements()结果是一组jsonb元素,因此,你需要添加的uid明确的转换与to_jsonb()功能jsonb,IN<@操作者更换:

WITH t(val) AS (VALUES 
    ('[1,2,3,4]'::JSONB) 
) 
SELECT TRUE 
FROM t,jsonb_array_elements(t.val) element 
WHERE to_jsonb(1) <@ element; 

对于你的情况,片段应调整为如下类似:

...SELECT ...,JSONB_ARRAY_ELEMENTS(in_users) user_ids
WHERE to_jsonb(uid) <@ user_ids...