Вставка уникального int в поле без первичного ключа

Я пытаюсь сделать SQL-запрос, используя INSERT INTO, чтобы скопировать ряд строк из таблицы, но я хочу, чтобы одно из полей (которое не является первичным ключом) имело новый, уникальный, int (я знаю это ужасный дизайн базы данных, но я не могу изменить структуру БД).

Вот упрощенный пример того, что я пытаюсь сделать:

    INSERT INTO Mytable
        (field1
        ,field2
        ,field3
        ,nonKeyUniqueInt)

    SELECT
        (field1
        ,field2
        ,field3
        ,(SELECT MAX(nonKeyUniqueInt)+1 FROM mytable)
    FROM
        mytable
    WHERE
        (conditions)

Однако это не работает, потому что запрос SELECT MAX выполняется только один раз, давая всем моим новым строкам одно и то же значение для этого поля. Учитывая следующие строки для копирования:

field1 field2 field3 nonKeyUniqueInt
x      y      z      1
a      b      c      2

Я получаю вывод:

field1 field2 field3 nonKeyUniqueInt
x      y      z      1
a      b      c      2
x      y      z      3
a      b      c      3

Возможно ли то, что я пытаюсь сделать?


person Slappywag    schedule 05.11.2014    source источник
comment
Примечание: SELECT MAX(...) + n обычно плохо сочетается с параллелизмом. Как насчет чего-то вроде SEQUENCE? Или вы не хотите поддерживать глобальный объект?   -  person Clockwork-Muse    schedule 05.11.2014
comment
@Clockwork-Muse Возможно, вы правы, но в основном это одноразовый запрос, и я хотел сделать это самым простым способом.   -  person Slappywag    schedule 05.11.2014


Ответы (1)


Проблема в том, что подзапрос оценивается один раз для insert, а не один раз для каждой строки. Решение состоит в том, чтобы использовать row_number():

INSERT INTO Mytable(field1, field2, field3, nonKeyUniqueInt)
    SELECT field1, field2, field3,
           x.maxk + row_number() over (order by (select NULL))
    FROM mytable CROSS JOIN
         (SELECT MAX(nonKeyUniqueInt) as maxk FROM mytable) x
    WHERE (conditions);

Я переместил максимальное вычисление в предложение FROM, чтобы было понятно, что оно оценивается только один раз.

person Gordon Linoff    schedule 05.11.2014
comment
Я думаю, что x в вашем SELECT должен быть x.maxk - person Andy Nichols; 05.11.2014
comment
@Энди Николс. . . Спасибо. - person Gordon Linoff; 05.11.2014
comment
Спасибо, это отлично работает в моем примере. Однако, когда я попытался поместить его в реальную базу данных, я получил сообщение об ошибке. Подзапрос вернул более 1 значения. Я не понимаю, как это могло быть сделано! О, я уверен, что у меня все получится. - person Slappywag; 05.11.2014