Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Базы данных и репортинг > Добавление стоки в SQL


Автор: Janger 9.10.2013, 13:42
В общем дело такое.
Есть SQL таблица, там уже имеется 26 записей. Мне необходимо дополнять от 27 и выше.
Я написал такой код.
Код

procedure TForm1.Button1Click(Sender: TObject);
begin
with DataModule2.ADOQuery1 do
begin
Close;
SQL.Clear;
SQL.Add('INSERT INTO Add_Name VALUES (27, ''Si'')');
ExecSQL;
DataModule2.ADOQuery1.Active:=false;
DataModule2.ADOQuery1.Active:=true;
end;
end;

Что происходит:
1) Я нажимаю на кнопку
2) http://%5BURL=http://s1.ipicture.ru/Gallery/Viewfull/31906604.html]Скриншот выплывающей ошибки[/url]
3) До этого заполненная таблица DBGrid1, тут же пустеет.
4) Я выхожу из программы, опять DBGrid1 заполнена. Только уже с тестом SI на 27 месте.
___________________
Как исправить?
Подскажите(((

Автор: Antimol 9.10.2013, 15:37
1. Скорее всего БД MS SQL Server.
2. Код мог бы выглядеть как то так (код написано в слепую, но принцип сохранился):

Код

begin
    with TADOQuery.Create(nil) do
    try
        Conection := (указать AdoConnection)
        SQL.Text :='INSERT INTO Add_Name VALUES (:ID, :NAME)';
        Parameters.ParamByName('ID').Value := 27;
        Parameters.ParamByName('NAME').Value := 'Name';
        ExecSQL;
    finally
        Free;
    end;
end;

3. Колонку ID можно создать как поле AutoIncrement тогда оно само будет подставляться, и не надо будет в коде указывать что ID = 27, а опустить его.
4. Ошибка говорит сама за себя, скорее всего полю Name установлено свойство первичного ключа (в таком случае не ясно зачем вообще ID, на Name можно было повесить только констрейнт на уникальность) и при вставке данных он говорит что запись с таким именем уже существует.

Автор: Vas 9.10.2013, 15:52
Цитата(Antimol @  9.10.2013,  15:37 Найти цитируемый пост)
4. Ошибка говорит сама за себя, скорее всего полю Name установлено свойство первичного ключа (в таком случае не ясно зачем вообще ID, на Name можно было повесить только констрейнт на уникальность) и при вставке данных он говорит что запись с таким именем уже существует. 

Там же сказано что значение дубликата 27. Причем здесь первичный ключ по name. Скорее всего Autoincrement на поле id уже установлен, но не факт.

Janger,  попробуй вставить запись без использования ID 
Код

with DataModule2.ADOQuery1 do
begin
Close;
SQL.Clear;
SQL.Add('INSERT INTO Add_Name (Name) VALUES (''Si'')');
ExecSQL;


И при получении ошибок такого типа, неплохо бы выбирать все записи в БД и смотреть значение первичного ключа.

Автор: Poseidon 9.10.2013, 22:34
Цитата(Antimol @  9.10.2013,  15:37 Найти цитируемый пост)
Код мог бы выглядеть как то так
Чем это принципиально отличается от кода, предложенного ТС? Ошибка эта все-равно выскачет.

Janger, в тексте ошибки все более чем очевидно. Какие могут быть вопросы?

Автор: Antimol 11.10.2013, 12:22
Цитата(Vas @  9.10.2013,  15:52 Найти цитируемый пост)
Там же сказано что значение дубликата 27

Скорее всего да, ошибку не дочитал до конца =).

Цитата(Poseidon @  9.10.2013,  22:34 Найти цитируемый пост)
Чем это принципиально отличается от кода, предложенного ТС?

1. Если уже пишем, так пишем так чтобы не попадать на сайт http://govnokod.ru/pascal
2. Для выполнения некого запроса мы каждый раз будем обращаться к  DataModule2.ADOQuery1? Может возникнуть ситуация что будет выполнен запрос  select, а потом insert и что в результате? У нас возникнет ситуация при которой данные с Grid'a исчезнут, если  DataModule2.ADOQuery1 конечно подвязан к нему.
3. Запрос с параметрами намного лучше чем конструкция вида:
Код

SQL.Add('INSERT INTO Add_Name VALUES (27, ''Si'')');

Если у нас в названии слово si'so тогда будет свал.
4. Вообще не понятная конструкция. Скорее всего выполнит один и тот же запрос 2 раза. (нужно проверить, если это так то из за этого и появляется ошибка)
Код

ExecSQL;
DataModule2.ADOQuery1.Active:=false;
DataModule2.ADOQuery1.Active:=true;

5. Минимизация кода 
Код

SQL.Clear;
SQL.Add('INSERT INTO Add_Name VALUES (27, ''Si'')');

можно заменить просто на:
Код

SQL.Text :='INSERT INTO Add_Name VALUES (:ID, :NAME)';


PS: Попался крупный проект который был написан в таком духе (>400 форм + куча г.кода и копипаста). Когда вижу что то подобное, стараюсь подсказать как лучше, конечно с моей точки зрения. =)

Автор: Vas 11.10.2013, 14:20
Цитата(Antimol @  9.10.2013,  15:37 Найти цитируемый пост)
 
with TADOQuery.Create(nil) do

Вот с таким кодом вы тоже на указанный вами сайт попадете. Что будет если приложение Ваше свалится, не попав в секцию Free?

Добавлено через 2 минуты и 1 секунду
Может все-таки стоит писать
Код

with TADOQuery.Create(Self) do

Автор: Antimol 11.10.2013, 15:08
Цитата(Vas @  11.10.2013,  14:20 Найти цитируемый пост)
Что будет если приложение Ваше свалится, не попав в секцию Free?

Будет утечка памяти только в том случае если в момент создания объекта  TADOQuery.Create(nil) произойдет свал.

Если свал произойдет после создания, тогда мы попадаем в секцию try .. funally end; которая гарантировано вызовет Free в любом случае  независимо оттого, что произойдет в предложении Try;

Грубо говоря код можно представить так:
Код

var
   Query: TADOQuery;
begin
    Query := TADOQuery.Create(nil);
    try
      //если свал/или  нет - выполнить код в секции finally
    finally
        Query.Free; //если так, тогда я использую FreeAndNil(Query); 
    end;
end;


Цитата(Vas @  11.10.2013,  14:20 Найти цитируемый пост)
Может все-таки стоит писать

Код

with TADOQuery.Create(Self) do


Так не всегда получится и нужно.  (У нас должен передаваться в Self - TComponent, мы можем написать модуль в котором есть метод с похожим кодом, который просто выполняет неким запрос с параметрами, тогда нужно будет передавать Self вместе со всеми параметрами)

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

Автор: Poseidon 11.10.2013, 16:17
Цитата(Antimol @  11.10.2013,  12:22 Найти цитируемый пост)
5. Минимизация кода 
Ну конечно. Тогда уже до конца нужно сравнивать:
Код

SQL.Text :='INSERT INTO Add_Name VALUES (:ID, :NAME)';
Parameters.ParamByName('ID').Value := 27;
Parameters.ParamByName('NAME').Value := 'Name';
ExecSQL;

или
Код

SQL.Text := 'INSERT INTO Add_Name VALUES (27, "Name")';
ExecSQL;
и это без учета того, что Parameters еще нужно объявить, создать и освободить. Крутая минимизация!

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

Добавлено через 2 минуты и 33 секунды
Цитата(Vas @  11.10.2013,  14:20 Найти цитируемый пост)
Что будет если приложение Ваше свалится, не попав в секцию Free?
Это как же надо так изловчиться, что бы свалиться на строке 
Код

with TADOQuery.Create(nil) do
?

Автор: Antimol 11.10.2013, 16:40
Цитата(Poseidon @  11.10.2013,  16:17 Найти цитируемый пост)

Код

SQL.Text := 'INSERT INTO Add_Name VALUES (27, "Name")';

Попробуйте передать вместо "Name"  => "Na'me" и увидем результат после выполнения.


Цитата(Poseidon @  11.10.2013,  16:17 Найти цитируемый пост)
 Parameters еще нужно объявить, создать и освободить

Если добавить к примеру в AdoQuery запрос тогда можно обращаться к параметрам без их явного создания.

Цитата(Poseidon @  11.10.2013,  16:17 Найти цитируемый пост)
Это как же надо так изловчиться, что бы свалиться на строке 

Скорее всего сделать свою обертку и в конструкторе, что то накрутить, было бы желание =), бывают такие перлы в коде попадаются что никогда не подумал бы.


Цитата(Poseidon @  11.10.2013,  16:17 Найти цитируемый пост)
 каким боком можно прилепить Ваш ответ к той ошибке


В общем ответ скрывался в 4.-м пункте,   но он скорее всего не верный, наверняка нужно удалить строчки 
Код

  DataModule2.ADOQuery1.Active:=false;
  DataModule2.ADOQuery1.Active:=true;

и все заработает, правда уже с другим номером (ИД)

Автор: Akella 12.10.2013, 13:10
Цитата(Janger @  9.10.2013,  13:42 Найти цитируемый пост)
Скриншот выплывающей ошибки


Тебе перевести было сложно?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)