Вложенный раздел в postgres - PullRequest
       35

Вложенный раздел в postgres

0 голосов
/ 04 сентября 2018

Я пытаюсь создать инфраструктуру реферального кода. Я хотел бы использовать до первых 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

...