Вверх ↑
Этот топик читают: Гость
Ответов: 16884
Рейтинг: 1239
#31: 2007-06-10 18:55:42 ЛС | профиль | цитата
nesco писал(а):
DELETE FROM _%1;
DROP TABLE _%1;
у меня нормально работает. А кто выдает это предупреждение? Может быть после удаления, ты даеш запрос на чтение данных из удаленной таблицы? А оно тебе в ответ = таблица закрыта.
nesco писал(а):
Что такое rowid и _rowid_
разницы не знаю никогда _rowid_ не пользовался
nesco писал(а):
Удаляю 3, даю VACUUM. В id -- 1,2,4, обращение веду по rowid, оно должно быть 1,2,3,
не подтверждается. После Vacuum нужно перечитать таблицу Select rowid,* from ...
карма: 25
Немного терпения! Дежурный экстрасенс скоро свяжется с Вами!
0
Разработчик
Ответов: 26073
Рейтинг: 2122
#32: 2007-06-10 23:05:25 ЛС | профиль | цитата
Tad писал(а):
ты даеш запрос на чтение данных из удаленной таблицы

К сопутствующе таблице я обращаюсь аж из другой формы и чтение ее при удалении записи в главной таблице вообще не предусматривалось. Надо внимательно посмотреть, может следующий запрос я выдаю слишком быстро (но точно не в запросе на удаление).

[size=-2]------ Добавлено в 21:34
И все же, есть запрос на пересчет PRIMARY KEY AUTOINCREMENT, или делать вручную?

[size=-2]------ Добавлено в 21:54
Ничерта не получается. Делаю вот так
DELETE FROM channels WHERE rowid = %1;
VACUUM;
SELECT rowid FROM channels;
Это последняя группа запросов в цикле запросов, по-этому стоит VACUUM. На выходе ловлю данные: удалил rowid = 5, на выходе прочитал 1,2,3,4,6,7. Пять и впомине нет. Следующий раз при удалении rowid = 5 эта группа запросов мягко игнорируется и не удаляет запись.

[size=-2]------ Добавлено в 23:00
Tad, вот твой доработанный пример. Я удаляю rowid = 5 только один раз, больше не могу. Что я делаю не так?

[size=-2]------ Добавлено в 23:05
Все, я понял после проверки. id не должен быть PRIMARY KEY, иначе rowid считывает его параметры. В примере я убрал id PRIMARY KEY и rowid начал выбирать абсолютные адреса строк.
карма: 22

0
файлы: 1db.zip [1.5KB] [337]
Ответов: 16884
Рейтинг: 1239
#33: 2007-06-11 10:17:58 ЛС | профиль | цитата
nesco, PRIMARY KEY - "первичный ключ" присваивается записи один раз ( при Insert into) и никакому пересчету не подлежит.
карма: 25
Немного терпения! Дежурный экстрасенс скоро свяжется с Вами!
0
Разработчик
Ответов: 26073
Рейтинг: 2122
#34: 2007-06-11 10:50:56 ЛС | профиль | цитата
nesco писал(а):
В примере я убрал id PRIMARY KEY и rowid начал выбирать абсолютные адреса строк

Это так и должно быть? У себя в базе я снял признак PRIMARY KEY с первого поля id и все у меня прекрасно заработало, и удаляется и вставляется по rowid.
Tad, ты не ответил удаляет ли у тебя а примере 5-ую запись? И как можно сделать, чтобы был id PRIMARY KEY и было абсолютное обращение к строкам?
карма: 22

0
Ответов: 2125
Рейтинг: 159
#35: 2007-06-11 11:01:08 ЛС | профиль | цитата
nesco писал(а):
есть запрос на пересчет PRIMARY KEY AUTOINCREMENT, или делать вручную?

Такого запроса нет и быть не должно. PRIMARY KEY используется для связи с другими таблицами. Значение этого поля никогда не должно меняться, т.к. этому числу могут соответствовать записи в других таблицах. Если бы даже такой запрос был, то что делать с остальными таблицами, в которых записано число, соответствующее PRIMARY KEY какой-то записи? Тоже менять? Автоматически? В SQLite такой возможности вроде нет.
карма: 1

0
Ответов: 1891
Рейтинг: 110
#36: 2007-06-11 20:46:33 ЛС | профиль | цитата
nesco, писал(а):
есть запрос на пересчет PRIMARY KEY AUTOINCREMENT, или делать вручную?


Можно сделать и не вручную

Например, есть такая таблица:
CREATE TABLE Temper (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name,temp)


idnametemp
111
222
343434
565656


Делаем так:
BEGIN TRANSACTION;
-- создаем временную таблицу Temper
CREATE TEMPORARY TABLE Temper_backup(name,temp);
-- копируем данные из таблицы Temper во временную таблицу Temper_backup
INSERT INTO Temper_backup SELECT name,temp FROM Temper;
-- удаляем таблицу Temper
DROP TABLE Temper;
-- создаем таблицу Temper
CREATE TABLE Temper(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name,temp);
-- вставляем данные из таблицы Temper_backup в таблицу Temper
INSERT INTO Temper (name,temp) SELECT name,temp FROM Temper_backup;
-- удаляем таблицу Temper_backup
DROP TABLE Temper_backup;
COMMIT;


и получаем:

idnametemp
111
222
33434
45656


tsdima писал(а):
Если бы даже такой запрос был, то что делать с остальными таблицами, в которых записано число, соответствующее PRIMARY KEY какой-то записи? Тоже менять? Автоматически? В SQLite такой возможности вроде нет.


для подобных случаев можно попробовать создать триггер
карма: 0
%time%
0
Разработчик
Ответов: 26073
Рейтинг: 2122
#37: 2007-06-11 21:37:08 ЛС | профиль | цитата
Alexbootch писал(а):
попробовать создать триггер

Вот про триггер подробнее можно? И еще. Когда необходимо прменять BEGIN TRANSACTION, и можно ли в простых базах обойтись без него?
карма: 22

0
Ответов: 16884
Рейтинг: 1239
#38: 2007-06-12 00:05:20 ЛС | профиль | цитата
nesco, если так делать, как предлагает Alexbootch, то нахрена тебе вообще id INTEGER PRIMARY KEY AUTOINCREMENT ? Объясни - понять не могу.
tsdima, тебе четко объяснил, что оно применяется для связи между таблицами и больше, по большому счету, ни для чего.
Живешь с женой - пить не дает. Живешь сам - закусить нечем.

карма: 25
Немного терпения! Дежурный экстрасенс скоро свяжется с Вами!
0
Разработчик
Ответов: 26073
Рейтинг: 2122
#39: 2007-06-12 00:34:54 ЛС | профиль | цитата
Да по большому счету, я его благополучно пох-л вмести с id. Без него прекрасно работает через rowid. Мне в той базе нумерация записей вообще не нужна, а в другой базе я вообще удалять ничего не буду, только писать в нее.
А про жену здорово подмечено
карма: 22

0
Ответов: 1891
Рейтинг: 110
#40: 2007-06-12 02:06:06 ЛС | профиль | цитата
nesco, писал(а):
Я понял так, что null для поля с AUTOINCREMENT'ом означает приращение на один.


Это дезинформация, т.к. когда значение поля равно NULL, это означает, что программа базы данных специально промаркировала это поле как не имеющее никакого значения для этой строки (или записи). Это отличается от просто назначения полю значения нуля или пробела, которые база данных будет обрабатывать также как и любое другое значение. Точно также, как NULL не является техническим значением, оно не имеет и типа данных.

Перевод с сайта SQLite писал(а):
Согласно стандарту SQL, "PRIMARY KEY" должен подразумевать "NOT NULL". К сожалению, в силу застаревшей ошибки кодирования, SQLite не соответствует этому требованию. SQLite допускает значения "NULL" в столбце "PRIMARY KEY". Мы хотели исправить SQLite в соответствии со стандартом (и мы могли это сделать), но выяснилось, что за время существования этого бага, многие пользователи восприняли его как фичу, и мы поостереглись фиксить этот баг, дабы в будущем не ломать коды пользователей. Итак, сейчас мы вынуждены допускать "NULL"-ы в столбцах "PRIMARY KEY". Однако, разработчики должны сознавать, что в будущем мы, возможно, изменим SQLite в соответствии со стандартом SQL и, следовательно, новые программы следует разрабатывать с учетом этого.



Tad писал(а):
NULL он и в Африке null, но в SQLite не всегда


Tad, почитай книжки по стандарту SQL, а потом спорь. NULL - значит пустой и не может быть чем-то другим

[size=-2]------ Добавлено в 01:56
nesco, писал(а):
Под транзакциями понимается тело цикла модификации, при успешном окончании которого, модификация считается успешно завершенной, иначе база не меняется вообще, я правильно понял? Значит приложение, записывающее в базу должно начинать цикл модификации с запроса BEGIN TRANSACTION, или это не обязательно, при условии, что другое приложение открывает базу только на просмотр и поиск (или уже ищет в базе до 100 000 тысяч записей). И чем операторные скобки BEGIN TRANSACTION должны заканчиваться -- END, COMMIT или ROLLBACK [TRANSACTION]?


BEGIN TRANSACTION

Код:
sql-оператор ::= BEGIN [ DEFERRED | IMMEDIATE | EXCLUSIVE ] [TRANSACTION [имя]]
sql-оператор ::= END [TRANSACTION [имя]]
sql-оператор ::= COMMIT [TRANSACTION [имя]]
sql-оператор ::= ROLLBACK [TRANSACTION [имя]]


Начиная с версии 2.0 SQLite поддерживает транзакции с откатом ("rollback") и атомарным подтверждением ("commit").

Опциональное имя транзакции игнорируется. В настоящее время SQLite не допускает вложенных транзакций.

База данных может быть изменена только в контексте транзакции. Любая команда, изменяющая базу данных (в основном, - это любая команда SQL, кроме "SELECT") автоматически начнет транзакцию, если та еще не начата. После выполнения команды автоматически начатая транзакция будет подтверждена ("committed").

Транзакция может быть начата вручную с помощью команды "BEGIN". Такая транзакция обычно сохраняется вплоть до следующей команды "COMMIT" или "ROLLBACK". Но, кроме того, "ROLLBACK" транзакции произойдет в случае закрытия базы данных, или если случится ошибка и "ROLLBACK" окажется способом разрешить конфликт. Чтобы больше узнать об алгоритме разрешения конфликтов "ROLLBACK", смотрите пункт "ON CONFLICT" этой документации.

В SQLite версии 3.0.8 и старше транзакции могут быть отложенными ("deferred"), немедленными ("immediate") или исключительными ("exclusive"). Отложенность означает, что база данных никак не блокируется до первого доступа к ней. Таким образом, при отложенной транзакции инструкция "BEGIN" ничего сама не делает. Блокировка не произойдет до первой операции чтения или записи. Первая же операция чтения создаст "SHARED" блокировку, а первая операция записи создаст "RESERVED" блокировку. Так как блокировка отложена до необходимости, другая нить или процесс могут создать отдельную транзакцию и выполнить запись в базу после "BEGIN"-а в текущей нити. Если транзакция является немедленной, "RESERVED" блокировка накладывается на все базы как только выполняется команда "BEGIN" независимо от того, когда будет использована база данных. После "BEGIN IMMEDIATE" вы можете быть уверены, что никакая нитка или процесс не смогут писать в базу и не смогут выполнить "BEGIN IMMEDIATE" или "BEGIN EXCLUSIVE". Тем не менее, другие процессы смогут продолжать читать базу данных. Исключительная транзакция устанавливает "EXCLUSIVE" блокировку на все базы данных. После "BEGIN EXCLUSIVE" вы можете быть уверены, что ни одна нитка или процесс не могут читать или писать в базу пока продолжается транзакция.

Описание блокировок "SHARED", "RESERVED" и "EXCLUSIVE" доступно здесь.

В SQLite версии 3.0.8 по умолчанию применяется отложенная транзакция. Для SQLite версий 3.0.0 - 3.0.7 отложенная транзакция является единственной возможной. В SQLite версии 2.8 и в более ранних все транзакции были исключительными.

Команда "COMMIT" не выполняется, пока не будут выполнены все, выполняющиеся в данный момент, команды SQL. Так, если "COMMIT" запускается в момент выполнения двух или более запросов "SELECT", он ничего не будет делать до тех пор, пока не закончится выполнение всех запросов "SELECT".

Попытка выполнить "COMMIT" может вернуть код "SQLITE_BUSY". Это означает, что другая нить или процесс читают из базы, и это помешало ее изменить. Когда "COMMIT" терпит неудачу подобным образом, транзакция остается активной, и "COMMIT" может быть повторен позже, когда чтение закончится.

[size=-2]------ Добавлено в 02:06
nesco, писал(а):
Вот про триггер подробнее можно?


CREATE TRIGGER

Код:
sql-оператор ::= CREATE [TEMP | TEMPORARY]
TRIGGER [IF NOT EXISTS] имя-триггера [ BEFORE | AFTER ]
событие-базы ON [имя-базы .] имя-таблицы
действие-триггера
sql-оператор ::= CREATE [TEMP | TEMPORARY]
TRIGGER [IF NOT EXISTS] имя-триггера INSTEAD OF
событие-базы ON [имя-базы .] имя-вьюхи
действие-триггера
событие-базы ::= DELETE |
INSERT |
UPDATE |
UPDATE OF список-столбцов
действие-триггера ::= [ FOR EACH ROW | FOR EACH STATEMENT ] [ WHEN выражение ]
BEGIN
шаг-триггера ; [ шаг-триггера ; ]*
END
шаг-триггера ::= оператор-update |
оператор-insert |
оператор-delete |
оператор-select


Оператор "CREATE TRIGGER" используется для добавления триггеров в схему базы данных. Триггеры - это операции (действие-триггера) на базе данных, которые исполняются автоматически, при возникновении указанного события (событие-базы).

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

В настоящее время SQLite поддерживает только триггеры "FOR EACH ROW", и не поддерживает триггеры "FOR EACH STATEMENT". Поэтому, необязательно явно указывать "FOR EACH ROW". "FOR EACH ROW" предполагает, что при запуске триггера SQL-операторы, специфицированные как "шаг-триггера", могут выполняться (в зависимости от пункта "WHEN") для каждой вставляемой, изменяемой или удаляемой строки в базе.

Элементы вставляемой, удаляемой или изменяемой строки доступны в пунктах "WHEN" и "шаг-триггера" с помощью ссылочных форм "NEW.имя-столбца" и "OLD.имя-столбца", где "имя-столбца" есть имя того столбца таблицы, к которому осуществляется доступ из триггера. Ссылки "OLD" и "NEW" могут использоваться только в триггерах и в "событиях-триггера", которым они соответствуют, как указано ниже:


* INSERT - Допустима ссылка "NEW"
* UPDATE - Допустимы ссылки "NEW" и "OLD"
* DELETE - Допустима ссылка "OLD"
Если указан пункт "WHEN", SQL-операторы, специфицированные как "шаг-триггера", выполняются только на тех строках, на которых выражение "WHEN" истинно. Если пункт "WHEN" не указан, то SQL-операторы выполняются на всех строках.

Специфицированное время-триггера ("BEFORE" или "AFTER") определяет, когда должны выполняться шаги-триггера относительно вставки, изменения или удаления данной строки.

Пункт "ON CONFLICT" может быть специфицирован как часть шага-триггера "UPDATE" или "INSERT". Но если пункт "ON CONFLICT" специфицирован как часть оператора, вызывающего выполнение триггера, то эта политика разрешения конфликтов используется вместо указанной в триггере.

Триггеры автоматически удаляются при удалении таблицы, с которой они ассоциированы.

Так же как на обыкновенных таблицах триггеры могут быть созданы на вьюхах с использованием "INSTEAD OF" в операторе "CREATE TRIGGER". Если на вьюхе определен один или несколько триггеров "ON INSERT", "ON DELETE" или "ON UPDATE", то, соответственно, выполнение на этой вьюхе операторов "INSERT", "DELETE" или "UPDATE" не является ошибкой. Таким образом, выполнение "INSERT", "DELETE" или "UPDATE" на вьюхе становится возможным с помощью ассоциированных с ней триггеров. Действительная таблица, на которую ссылается вьюха, не модифицируется (если только это не заложено явно в триггер).

Пример:

Предположим, что записи о клиентах хранятся в таблице "customers", и что записи о заказах хранятся в таблице "orders". Следующий триггер гарантирует, что когда клиент меняет свой адрес, все соответствующие ему заказы переназначаются:

Код:
CREATE TRIGGER update_customer_address UPDATE OF address ON customers
BEGIN
UPDATE orders SET address = new.address WHERE customer_name = old.name;
END;


С созданием этого триггера, выполнение команды

Код:
UPDATE customers SET address = '1 Main St.' WHERE name = 'Jack Jones';


автоматически приведет к выполнению следующей:

Код:
UPDATE orders SET address = '1 Main St.' WHERE customer_name = 'Jack Jones';


Заметим также, что триггеры могут вести себя странно, если создаются на таблицах с полями "INTEGER PRIMARY KEY". Если триггер "BEFORE" модифицирует поле "INTEGER PRIMARY KEY" в строке, которая впоследствии должна быть изменена командой, которая влечет запуск этого триггера, то изменение может не произойти. Чтобы это обойти, можно декларировать столбец таблицы как "PRIMARY KEY" вместо "INTEGER PRIMARY KEY".

Специальная SQL-функция "RAISE()" может быть использована внутри программы-триггера в следующем синтаксисе:

Код:
функция-raise ::= RAISE ( ABORT, сообщение-об-ошибке ) |
RAISE ( FAIL, сообщение-об-ошибке ) |
RAISE ( ROLLBACK, сообщение-об-ошибке ) |
RAISE ( IGNORE )


Если во время выполнения текущей программы-триггера она вызывается в одной из первых трех форм, то выполняется указанный обработчик "ON CONFLICT" (то есть "ABORT", "FAIL" или "ROLLBACK") и текущий запрос убивается. Ошибочный код "SQLITE_CONSTRAINT" возвращается пользователю вместе с указанным сообщением об ошибке.

Когда вызывается "RAISE(IGNORE)", остаток текущей программы триггера, оператор, ставший причиной запуска триггера, и последующие программы триггера, которые должны были бы выполниться, не будут выполнены. Изменения базы данных не будут откачены. Если оператор, ставший причиной запуска программы триггера, сам является частью какой-то программы триггера, то эта вторая программа триггера продолжит выполнение с начала следующего шага.

Триггеры могут быть удалены с помощью оператора "DROP TRIGGER".
карма: 0
%time%
0
Разработчик
Ответов: 26073
Рейтинг: 2122
#41: 2007-06-12 02:23:54 ЛС | профиль | цитата
Alexbootch, ну спасибо. Во блини -- чистая вешалка, похлеще Delphi. Это тебе не контролы назначать и KOL'ы портировать.
карма: 22

0
Ответов: 3655
Рейтинг: 69
#42: 2007-06-12 03:17:43 ЛС | профиль | цитата
nesco писал(а):
Во блини -- чистая вешалка, похлеще Delphi. Это тебе не контролы назначать и KOL'ы портировать.

А я говорил давайте возьмём какую нибудь базу попроще без всяких заморочек с SQL запросами .
карма: 0

0
Ответов: 1891
Рейтинг: 110
#43: 2007-06-12 03:32:43 ЛС | профиль | цитата
Вячеслав, нет там ничего сложного
карма: 0
%time%
0
Ответов: 3655
Рейтинг: 69
#44: 2007-06-12 13:22:50 ЛС | профиль | цитата
Alexbootch писал(а):
нет там ничего сложного

Ага ,пятая страница пошла.
карма: 0

0
Разработчик
Ответов: 26073
Рейтинг: 2122
#45: 2007-06-12 13:31:42 ЛС | профиль | цитата
Alexbootch писал(а):
Вячеслав, нет там ничего сложного

Ну да -- ничего сложного -- это когда въедешь.
карма: 22

0
Сообщение
...
Прикрепленные файлы
(файлы не залиты)