Как я могу вставить строку и добавить номер строки, чтобы обеспечить уникальность? - PullRequest
0 голосов
/ 31 августа 2018

У меня есть таблица users с электронными письмами.

В users есть столбцы user_id и email

У меня также есть список user_referral_codes.

У user_referral_codes есть user_id, который является внешним ключом user_id пользователя. Также имеется столбец referral_code.

referral_code будет первой частью пользовательского email.

Если адрес электронной почты johnsmith99@gmail.com, тогда referral_code будет установлен на johnsmith.

Это прекрасно работает:

`INSERT INTO flock_auth.user_referral_codes (user_id, referral_code)
VALUES($1, LEFT(LEFT($2, strpos($2, '@') - 1), 12));`

Однако, могут быть добавлены два электронных письма одно за другим, например:

johnsmith@gmail.com и johnsmith@aol.com

В этом случае я бы хотел, чтобы вторая вставка стала:

johnsmith1.

Для начальных UPDATE существующих пользователей и реферальных кодов это работает просто отлично:

UPDATE auth.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
        auth.users.*,
        row_number() OVER (
          PARTITION BY LEFT(LEFT(email, strpos(email, '@') - 1), 12)
          ORDER BY id
        ) AS seqnum
      FROM auth.users
    ) AS u
  WHERE urc.user_id = u.id;

Я попытался адаптировать этот код для вставок.

INSERT INTO auth.user_referral_codes (user_id, referral_code)
  SELECT (
    $1,
    LEFT(LEFT(email, strpos(email, '@') - 1), 12)
    || (CASE WHEN seqnum > 1 THEN (seqnum-1)::TEXT ELSE '' END)
    )
    FROM (
      SELECT
        auth.users.*,
        row_number() OVER (
          PARTITION BY LEFT(LEFT(email, strpos(email, '@') - 1), 12)
          ORDER BY id
        ) AS seqnum
      FROM auth.users
    ) AS u
  WHERE $1 = u.id;

Ошибка возвращается как: INSERT has more target columns than expressions

Как я могу сделать эту работу?

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Теперь это работает:

INSERT INTO auth.user_referral_codes (user_id, referral_code)
  SELECT
    $1,
    LEFT(LEFT(email, strpos(email, '@') - 1), 12)
    || (CASE WHEN seqnum > 1 THEN (seqnum-1)::TEXT ELSE '' END)
    FROM (
      SELECT
        auth.users.*,
        row_number() OVER (
          PARTITION BY LEFT(LEFT(email, strpos(email, '@') - 1), 12)
          ORDER BY id
        ) AS seqnum
      FROM auth.users
    ) AS u
  WHERE $1 = u.id;

Проблема заключалась в лишних скобках и вложении операторов выбора.

0 голосов
/ 31 августа 2018

Не вдаваясь в ваш код, условно я бы сделал что-то вроде этого:

with parsed as (
  select
    email,
    left (split_part (email, '@', 1), 12) as user_id,
    row_number() over
        (partition by left (split_part (email, '@', 1), 12) order by id) - 1 as rn
  from auth.users
)
select
  email,
  case
    when rn > 0 then user_id || rn
    else user_id
  end as user_id
from parsed

Вы можете обойтись без CTE, но это делает вещи немного чище.

...