2016-02-27 97 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...