Я пытаюсь создать инфраструктуру реферального кода. Я хотел бы использовать до первых 12 символов электронного письма пользователя, выведенного с целым числом:
Итак, учитывая трех пользователей с электронными письмами bob@gmail.com
, bob@hotmail.com
и bob@yahoo.com
, я хотел бы сгенерировать коды bob
, bob1
и bob2
.
Я сделал это с помощью следующего sql:
UPDATE user_referral_codes urc
SET referral_code = (
LEFT(LEFT(email, strpos(email, '@') - 1), 12)
|| (CASE WHEN seqnum > 1 THEN (seqnum-1)::TEXT ELSE '' END)
)
FROM (
SELECT
users.*,
row_number() OVER (
PARTITION BY LEFT(LEFT(email, strpos(email, '@') - 1), 12)
ORDER BY id
) AS seqnum
FROM users
) AS u
WHERE urc.user_id = u.id;
Это прекрасно работает, однако есть два случая с краями:
1) Реферальные коды должны быть глобально уникальными, поэтому добавление пользователей bob1@gmail.com
и bob2@gmail.com
в микс должно привести к следующим парам:
bob@gmail.com | bob
bob@hotmail.com | bob3
bob@yahoo.com | bob4
bob1@gmail.com | bob1
bob2@gmail.com | bob2
Как я могу объяснить это?
2) Есть второй код, coupon_codes. Как мне также обеспечить отсутствие дублирования с этой таблицей?
например. если код купона bob2
существует, то bob2@gmail.com
также должен получить реферальный код bob21
?
Пример схемы:
CREATE TABLE users(
id bigint NOT NULL PRIMARY KEY,
email TEXT NOT NULL UNIQUE
);
CREATE TABLE user_referral_codes(
user_id bigint NOT NULL REFERENCES users (id),
referral_code TEXT
);
CREATE TABLE coupon_codes(
code_id TEXT
);
INSERT INTO users(id, email) VALUES(1, 'bob@flockcover.com');
INSERT INTO users(id, email) VALUES(2, 'bob@google.com');
INSERT INTO users(id, email) VALUES(3, 'bob@gmail.com');
INSERT INTO users(id, email) VALUES(4, 'bob1@gmail.com');
INSERT INTO user_referral_codes(user_id) VALUES(1);
INSERT INTO user_referral_codes(user_id) VALUES(2);
INSERT INTO user_referral_codes(user_id) VALUES(3);
INSERT INTO user_referral_codes(user_id) VALUES(4);
INSERT INTO coupon_codes(code_id) VALUES('bob2');
Пример запроса на выборку, демонстрирующий текущее (неполное) поведение:
SELECT LEFT(LEFT(email, strpos(email, '@') - 1), 12)
|| (CASE WHEN seqnum > 1 THEN (seqnum-1)::TEXT ELSE '' END)
FROM (
SELECT
users.*,
row_number() OVER (
PARTITION BY LEFT(LEFT(email, strpos(email, '@') - 1), 12)
ORDER BY id
) AS seqnum
FROM users
) as u;
Ссылка sqlfiddle, демонстрирующая проблему:
http://sqlfiddle.com/#!17/0a6ea