LINUX.ORG.RU

[SQLite] Не могу создать базу с двумя автоинкрементирущимися полями.

 


0

0

Здравствуйте!

Нужно мне создать в SQLite базу, в которой бы было два автоинкрементирующихся поля. Вот такую:

CREATE TABLE list(
  id       INTEGER PRIMARY KEY AUTOINCREMENT, 
  order_id INTEGER AUTOINCREMENT,
  time     DATETIME,
  name     TEXT
);

Проблема в том, что SQLite не может создать базу с такой структурой. Выдается ошибка:

Error: near "AUTOINCREMENT": syntax error

Если в поле order_id убрать ключевое слово AUTOINCREMENT, то база данных создается. Но поле order_id уже не автоинкрементируется при добавлении записи.

И вместо автоматизации процесса присвоения уникального номера, нужно писать в приложении выборку максимального номера по столбцу order_id, инкрементировать его, и записывать полученное число в новую запись. Что неслабо напрягает.


Вопрос. Поддерживает ли SQLite автоинкремент в нескольких столбцах? Или автоинкремент возможен только для столбца PRIMARY KEY, и как следствие - только для одного столбца в таблице?


У тебя таблица с двумя автоинкрементирущимися полями, а не база. Выкини поле order_id (оно итак всегда будет равно id)

aydar ★★★★★
()
Ответ на: комментарий от aydar

У тебя таблица с двумя автоинкрементирущимися полями, а не база.

Ну да, таблица.


Выкини поле order_id (оно итак всегда будет равно id)

???

id - это уникальный идентификатор.

order_id - это последовательность, в которой нужно выстраивать записи.

С чего бы order_id итак всегда будет равно id ? Это совершенно разные вещи.

xintrea
() автор топика
Ответ на: комментарий от name_no

> а смысл?

в том, что в таблице хранится информация, в какой последовательности надо выстраивать записи. Для этого и используется поле order_id.

xintrea
() автор топика

Он тебе намекает, кто нужно проводить нормализацию базы, ибо лишнее поле в таблице - не есть хорошо.

Я правильно понял, что между id и order_id есть зависимость по всей таблице? Если да, то значит order_id не нужно.

shahid ★★★★★
()
Ответ на: комментарий от shahid

> Он тебе намекает, кто нужно проводить нормализацию базы, ибо лишнее поле в таблице - не есть хорошо.

Я правильно понял, что между id и order_id есть зависимость по всей таблице? Если да, то значит order_id не нужно.


Йоба, это чо значит, что указывать последовательность записей в самой таблице нельзя? Обязательно нужно создавать отдельную сортирующую таблицу, в которой будут перечислены пары id <-> order_id, причем столбец order_id должен быть PRIMARY KEY, чтоб автоинкрементирование работало?

И помимо этого надо писать следилку, чтобы в сортирующей таблице удалялась соответствующая запись, если в основной таблице удалена запись? Причем, удаление в сортирущей таблице будет дико тормозить, так как ключ в ней построен по полю order_id а не id?

xintrea
() автор топика
Ответ на: комментарий от xintrea

Они Вам намекают что при вставке новой записи она получает заведомо максимальные значения в оба поля с autoincrement, т.е. по какому сортировать без разницы - одно избыточно.

tux2002
()
Ответ на: комментарий от xintrea

в том, что в таблице хранится информация, в какой последовательности надо выстраивать записи. Для этого и используется поле order_id.

а для чего тогда нужен id?

name_no ★★
()
Ответ на: комментарий от xintrea

SQLite поддерживает автоинкремент только в поле, отмеченном INTEGER PRIMARY KEY.

Oracle DBMS не поддерживает инкремент вообще.

В постгресе есть тип serial, который создает автоматом последовательность и триггер before insert, как и оракл. Враппер по сути. И ты сделай также, раз уж надо.

shahid ★★★★★
()
Ответ на: комментарий от xintrea

> в том, что в таблице хранится информация, в какой последовательности надо выстраивать записи. Для этого и используется поле order_id.

1) order_id не очень удачное название. У меня ассоциируется с неким номером заказа. лучше переименуйте в sort_order

2)
insert into list
(sort_order, time, name)
values(
case when (select max(sort_order) from test) IS NULL then 0 else (select max(sort_order) from test)+1 end,
'<TIME>',
'<NAME>'
);

Slavaz ★★★★★
()
Ответ на: комментарий от xintrea

http://www.sqlite.org/cvstrac/wiki?p=UnsupportedSql

Цытато

AUTO_INCREMENT is possibly the worst way of doing unique ids for tables. It requires cached per-connection-handle last_insert_id() values. And you're probably already familiar with how much of a hack THAT is.

shahid ★★★★★
()
Ответ на: комментарий от xintrea

>С чего бы order_id итак всегда будет равно id ? Это совершенно разные вещи.
C того, что ежели они оба с автоинкрементом, то при каждой вставке оба будут увеличиваться на единицу. Если они равны изначально - будут равны и дальше. Если отличаются - то и дальше будут отличаться на ту же величину.
Если вам нужно переодически менять очередность - то автоинкремент order_id не нужен совершенно. Если не нужно - сортируйте по id, в чем проблема?

iSage ★★★★
()
Ответ на: комментарий от iSage

> C того, что ежели они оба с автоинкрементом, то при каждой вставке оба будут увеличиваться на единицу. Если они равны изначально - будут равны и дальше. Если отличаются - то и дальше будут отличаться на ту же величину.

Есть база, например, передовиков производства. Впереди самые лучшие по итогам месяца, позади похуже.

id order_id Name
1 2 Вася
2 1 Петя
5 7 Саша
7 5 Коля
9 9 Витя

То есть, передовики перечисляются:

Петя
Вася
Коля
Саша
Витя

Если вам нужно переодически менять очередность - то автоинкремент order_id не нужен совершенно. Если не нужно - сортируйте по id, в чем проблема?


Как вы собираетесь, не изменяя уникального идентификатора человека (id), сортировать их список?

xintrea
() автор топика
Ответ на: комментарий от name_no

>> в том, что в таблице хранится информация, в какой последовательности надо выстраивать записи. Для этого и используется поле order_id.

а для чего тогда нужен id?


Для чего нужен уникальный идентификатор? Наверняка не для сортировки записей, которая может меняться со временем.

xintrea
() автор топика
Ответ на: комментарий от Slavaz
> insert into list
> (sort_order, time, name) 
> values(
> case when (select max(sort_order) from test) IS NULL then 0 
> else (select max(sort_order) from test)+1 end,
> '<TIME>',
> '<NAME>'
> );

from list наверно?

insert into list
(sort_order, time, name) 
values(
case when (select max(sort_order) from list) IS NULL then 0 else (select max(sort_order) from list)+1 end,
'<TIME>',
'<NAME>'
);

Кстати, это допустимый SQLite синтаксис?

xintrea
() автор топика
Ответ на: комментарий от xintrea

Наверняка не для сортировки записей, которая может меняться со временем.

если сортировка будет меняться - тебе не нужен autoincrement на order_id. Иначе сортировку можно делать по id и он нужен в том числе и для этих целей, раз уж всё равно собираешься сортировать в порядке добавления. Я тебе пытаюсь наглядно продемонстрировать, что у тебя одно поле лишнее. Посмотри сам. Одно из них не нужно. Если хочешь сортировать не в порядке добавления, да ещё и с возможностью изменения порядка сортировки - тебе не нужен autoincrement.

Впереди самые лучшие по итогам месяца, позади похуже.

это вообще, да. вот что для такого совершенно не подходит - так это поле order_id непосредственно в таблице работников. А если через пару месяцев будет два варинта вортировки - по передовичности труда и по повышенной активности участия в субботниках? Учи нормализацию баз данных, а пока вот тебе очевидный фикс. Работники труда - в одну таблицу. Показатели труда - в другую. Связь внешними ключами. Выбираешь показатели труда за последнюю неделю, джоинишь с работниками - получаешь отсортированный список. И не нужно делать ручной апдейт таблицы каждую неделю.

name_no ★★
()
Ответ на: комментарий от xintrea

Я не вижу тут автоинкремента поля order_id. И не нужен он тут.
И как уже сказали выше - такую сортировку лучше в отдельную таблицу.

iSage ★★★★
()
Ответ на: комментарий от xintrea

AUTO_INCREMENT is possibly the worst way of doing unique ids for tables. It requires cached per-connection-handle last_insert_id() values. And you're probably already familiar with how much of a hack THAT is.

AUTO_INCREMENT скорее всего худший метод получения уникальных id для строк таблиц. Оно требует кешируемых для каждого коннекшна значений last_insert_id(). И вам, наверное, и так известно, КАКОЙ это костыль.

iSage ★★★★
()
Ответ на: комментарий от xintrea

> from list наверно?
тьфу, да. сделал у себя тестилку и не поменял...

Кстати, это допустимый SQLite синтаксис?

в sqlite3 и тестировал. Это SQL99.


Slavaz ★★★★★
()
Ответ на: комментарий от xintrea

Написано, что банальный autoincrement - это не Ъ и костыль, работает через вызов last_insert_id() и реализуем лишь только на однопоточной базе.

shahid ★★★★★
()
Ответ на: комментарий от name_no

> если сортировка будет меняться - тебе не нужен autoincrement на order_id. Иначе сортировку можно делать по id и он нужен в том числе и для этих целей, раз уж всё равно собираешься сортировать в порядке добавления.

В том то и дело, что автоинкремент нужен. Когда создается новая запись, я хотел бы чтоб в order_id записывалось автоинкрементированное значение. Тогда без лишних телодвижений получается, что только что добавленный товарищ будет в конце списка. Там ему и место.

Я пример с васей-петей привел условно. На деле, в моей системе мне нужна возможность выводить записи в той последовательности, которая указана в order_id. И все. Поэтому, этот order_id - обязательное поле, и у меня оно есть в каждой базе (так же как и id).

Другими словами, пользователь должен иметь возможность легко перемещать записи вверх-вниз. Перемещать в любой базе, которая есть в моей системе. Это решается введением поля order_id. Городить огород с отдельной сортировочной базой для каждой базы - не хочется.

xintrea
() автор топика
Ответ на: комментарий от shahid

> AUTOINCREMENT

1 2 Вася

2 1 Петя


когда_вы_говорите_вы_бредите.jpg



В программе есть режим, который переставляет значения order_id в записях, согласно желаниям пользователя. В чем тут бред?

xintrea
() автор топика
Ответ на: комментарий от xintrea

Городить огород с отдельной сортировочной базой для каждой базы - не хочется.

Вы путаете базу и таблицу. Поле есть у Вас в каждой *таблице*, городить огород с сортировочными *таблицами* для каждой *таблицы* и т.д.

Вынужден признать, что Вы правы. Делайте триггер - это более правильно, чем AUTOINCREMENT.

name_no ★★
()

Ересь полная. Зачем автоинкремент? Это абсолютно нелогично и пахнет магией. Выше товарищи корректно высказались - либо триггер, либо на уровне логики добавления новой строки в базу (сохранение нового экземпляра какого-то там объекта) забирайте MAX(order_id). Опять же, order_id, как отметились выше - абсолютно бредовое название для параметра, который отвечает за сортировку.

solshark
()

Максимальное значение id всегда равно количеству записей.
Также, максимальное значение order_id будет равно количеству записей. Получается max(order_id) = max(id).

Создай триггер (after insert), который будет записывать в order_id значение id вставленной записи. Таким образом, каждая новая запись будет последней в сортировке до того, как ты своей процедурой все не пересортируешь.

aydar ★★★★★
()
Ответ на: комментарий от aydar

>Максимальное значение id всегда равно количеству записей. Также, максимальное значение order_id будет равно количеству записей. Получается max(order_id) = max(id).

Ну по сути верно, но не факт. Допустим, удалил какую-то запись? max(id)!=count()

Но это не важно. На счет триггера - хорошее дело, но логика в этом случае скрыта в недрах базы. А ну как другой девелопер будет саппортить? Или надо будет переехать на другую СУБД? Т.е. я не то чтобы спорил: в простом случае триггер - самое очевидное и быстрое решение. Но это как-то ... некрасиво. Вот.

solshark
()
Ответ на: комментарий от solshark

>Ну по сути верно, но не факт. Допустим, удалил какую-то запись? max(id)!=count()
После удаления станет max(id) > count(). При вставке записи (когда order_id = id) дублирования order_id не будет

aydar ★★★★★
()
Ответ на: комментарий от aydar

Ага. Вообще я просто так, к фразе «Максимальное значение id всегда равно количеству записей.» прицепился. Так сказать, для уточнения.

solshark
()
Ответ на: комментарий от solshark

кстати, в sqlite пустые поля как сортируются? Если как в оракле, т.е. вконце, то можно и без триггера обойтись (делать order_by = NULL). новые записи при сортировке по order_id всегда будут вконце, пока туда не запишут какое-нибудь число.

aydar ★★★★★
()
Ответ на: комментарий от aydar

> Максимальное значение id всегда равно количеству записей.

Также, максимальное значение order_id будет равно количеству записей. Получается max(order_id) = max(id).

Создай триггер (after insert), который будет записывать в order_id значение id вставленной записи. Таким образом, каждая новая запись будет последней в сортировке до того, как ты своей процедурой все не пересортируешь.



Во, это разумный подход.

xintrea
() автор топика
Ответ на: комментарий от Deleted

> атомарен?

halturin

Не увиливайте от работы, пишите триггер.

berrywizard ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.