Online игроки могут дополнительно доступ покупную игровая комната 1 или игровая комната 2.Использование JSONB_ARRAY_ELEMENTS с 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, Apple, Game Center и т.д.)
Я пытаюсь создать хранимую функцию, которая будет принимать список числовых идентификаторов пользователей (как массив 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.
Есть ли конкретные причины, почему вы использовали бы массив 'jsonb'? Почему бы не использовать массив 'int []'? – Patrick
Да, я хотел бы использовать JSON, потому что это мое мобильное приложение говорит с бэкэндом PHP + PostrgreSQL. Я уверен, что моя проблема разрешима с JSON, я просто пропускаю что-л. незначительный. –