Решено: SQLite3 + Select

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Petrakoff Sergey
новенький
Сообщения: 33
Зарегистрирован: 08.12.2011 11:42:17

Сообщение Petrakoff Sergey »

Vadim писал(а):3. Метод ExecSQL используется только тогда, когда Вам не нужно получать данные. Во всех других случаях этот метод совершенно бессмысленен.

Алгоритм действий:
1. Получить из таблицы TKategorii значение IDKATEGOR текущей строки.
2. Подставить это значение в запрос к Lekarstva в секцию WHERE, не забыв преобразовать в строковый тип (т.к. запрос - это строка ;) ).
3. Открыть запрос методом Open.
Всё. :)

Код: Выделить всё

    QLek.Close;
    QLek.SQL.Clear;
    QLek.SQL.Add('select * from Lekarstva where IDKATEGOR='+QKAT.FieldByName('IDKATEGOR').AsString);
    QLek.Open;

100%-но работающий код. И единственный, который нужен. ;)

Ну, у меня в принципе, было то же самое. Разве что метод ExecSQL был лишним, хотя и с ним работает.
Проблема решилась следующим образом:
1. Из-за собственной невнимательности.
Дело в том, что базу я брал готовую, правда Paradox-овскую (чтобы ее перевести в SQLite, пришлось написать отдельную процедуру).
Оказалось, в таблице лекарств в категории IDKATEGOR=1 не было лекарств. При открытии таблиц, указатель ставится на первую запись, и естественно в DBGrid2 ничего не отображалось. После добавления нужных данных в таблицу, в DBGrid2 они отобразились. Однако, если в первом гриде выбрать другую категории, во втором гриде ничего не менялось.
2. Поэтому для первого грида необходимо ставить обработчик OnCellClick в котором надо повторить запрос.
v-t-l
энтузиаст
Сообщения: 744
Зарегистрирован: 13.05.2007 16:27:22
Откуда: Belarus

Сообщение v-t-l »

Все просто :wink:

Добавлено спустя 9 минут 24 секунды:
1.Обратить внимание на свойство SQLQuery2.DataSource.
2.Параметр (:IDKATEGOR) в SQLQuery2.SQL должен называться так же, как ключевое поле в SQLQuery1
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Petrakoff Sergey
новенький
Сообщения: 33
Зарегистрирован: 08.12.2011 11:42:17

Сообщение Petrakoff Sergey »

v-t-l
Спасибо, что уделили время и сделали пример. У Вас реализация гораздо изящней.
v-t-l
энтузиаст
Сообщения: 744
Зарегистрирован: 13.05.2007 16:27:22
Откуда: Belarus

Сообщение v-t-l »

Пожалуйста. :)
Кстати, запихивать каждую таблицу в отдельную базу SQLite (отдельный файл) не нужно, иначе создать запрос, содержащий обращение к двум таким таблицам одновременно, НЕ ПОЛУЧИТСЯ.
Последний раз редактировалось v-t-l 20.12.2020 22:47:46, всего редактировалось 1 раз.
Petrakoff Sergey
новенький
Сообщения: 33
Зарегистрирован: 08.12.2011 11:42:17

Сообщение Petrakoff Sergey »

v-t-l писал(а):Кстати, запихивать каждую таблицу в отдельную базу SQLite (отдельный файл) не нужно, иначе создать запрос, содержащий обращение к двум таким таблицам одновременно, НЕ ПОЛУЧИТЬСЯ.

Ну, вот опять проблема. Чтобы не плодить темы, решил здесь спросить, тем более вопросы, в принципе взаимосвязаны.
У меня как раз таблицы в отдельных файлах. В одном файле одна таблица. Пытаюсь создать один файл базы с несколькими таблицами. Поскольку с запросами я пока не очень подружился, пытался делать через TFieldDefs. Не получается.

Код: Выделить всё

Sqlite3.CreateTable(Table_Name);
Sqlite3.TableName:= Table_Name;
NewFields.Create(nil);
Sqlite3.FieldDefs.Assign(NewFields); // EXTERNAL SIGSEGV

Никак не пойму, как для новой таблицы добавить свой FieldDefs
v-t-l
энтузиаст
Сообщения: 744
Зарегистрирован: 13.05.2007 16:27:22
Откуда: Belarus

Сообщение v-t-l »

Petrakoff Sergey писал(а):Пытаюсь создать один файл базы с несколькими таблицами.Поскольку с запросами я пока не очень подружился,

http://sqliteadmin.orbmu2k.de/
http://sqliteman.com/
http://sqlitebrowser.sourceforge.net/
и еще пару вагонов :D
Petrakoff Sergey
новенький
Сообщения: 33
Зарегистрирован: 08.12.2011 11:42:17

Сообщение Petrakoff Sergey »

Так я это уже сделал, но это же "вручную"! А хотелось программно, чтобы не только эти два, а любые файлы.
Как я уже писал, перевожу файлы Paradox.
v-t-l
энтузиаст
Сообщения: 744
Зарегистрирован: 13.05.2007 16:27:22
Откуда: Belarus

Сообщение v-t-l »

Petrakoff Sergey писал(а):А хотелось программно, чтобы не только эти два, а любые файлы.

Код: Выделить всё

  SQLScript1.Script.Text :=
  'BEGIN TRANSACTION;'#13#10+
  'CREATE TABLE TKategorii (IDKATEGOR INTEGER PRIMARY KEY, KATEGOR VARCHAR(50));'#13#10+
  #13#10+
  'CREATE TABLE Lekarstva ('#13#10+
  '  IDKATEGOR INTEGER,'#13#10+
  '  IDLEKARSTVO INTEGER PRIMARY KEY,'#13#10+
  '  LEKARSTVO VARCHAR(50)'#13#10+
  ');'#13#10+
  #13#10+
  'COMMIT;';
  SQLScript1.Execute;
Petrakoff Sergey
новенький
Сообщения: 33
Зарегистрирован: 08.12.2011 11:42:17

Сообщение Petrakoff Sergey »

Спасибо! Буду разбираться. Но я имел в виду не совсем то.
Создавать один файл с одной таблицей я умею, правда через TFieldDefs.
У меня не получается создать вторую таблицу внутри одной базы. У меня было два файла Lekarstva.db и Kategorii.db, которые содержали по одной таблице (Lekarstva и TKategorii). В Вашем примере имеется всего одна база Lekarstva.db, которая содержит две таблицы. Вот сделать так у меня и не получается (программно). Новый FieldDefs я создаю:

Код: Выделить всё

  // создание новой таблицы
  NewFields:= TFieldDefs.Create(nil);
  Sqlite3.FieldDefs.Assign(NewFields);
  for i:= 0 to SQLite3_Old.Fields.Count - 1 do
  with NewFields do
  begin
    Add(SQLite3_Old.Fields.Fields[i].FieldName,
    SQLite3_Old.Fields.Fields[i].DataType,
    SQLite3_Old.Fields.Fields[i].Size);
  end; 
  Sqlite3.CreateTable(Table_Name);
  // копирование данных
  SQLite3_Old.First;
  Sqlite3.Open;
  while not SQLite3_Old.EOF do
  begin
    Sqlite3.Append;
    for i:= 0 to SQLite3_Old.Fields.Count - 1 do
    begin
      Sqlite3.Fields.Fields[i].Value:= SQLite3_Old.Fields.Fields[i].Value;
    end;
    SQLite3_Old.Next;
  end;

Новая таблица в базе создается (пустая), но не получается скопировать данные. При прогоне выскакивает "Invalid variant type cast" и данные в первой таблице затираются, т.е. скорее всего программа использует FieldDefs первой таблицы, а не NewFields. Как сделать, чтобы программа использовала NewFields не получается.
v-t-l
энтузиаст
Сообщения: 744
Зарегистрирован: 13.05.2007 16:27:22
Откуда: Belarus

Сообщение v-t-l »

Petrakoff Sergey писал(а):

Код: Выделить всё

Sqlite3.Fields.Fields[i].Value:= SQLite3_Old.Fields.Fields[i].Value;

???

Код: Выделить всё

Sqlite3.Fields[i].Value:= SQLite3_Old.Fields[i].Value;
Petrakoff Sergey
новенький
Сообщения: 33
Зарегистрирован: 08.12.2011 11:42:17

Сообщение Petrakoff Sergey »

v-t-l писал(а):???

Sqlite3.Fields[i].Value:= SQLite3_Old.Fields[i].Value;

Та же самая ошибка!

Добавлено спустя 2 минуты 13 секунд:
И все-таки я думаю, что скорее всего программа использует FieldDefs первой таблицы, а не NewFields.

Добавлено спустя 7 минут 11 секунд:
Приведенный мною код работает, если создавать только одну таблицу.

Код: Выделить всё

// создание таблицы
  Sqlite3.FieldDefs.Clear;
  Sqlite3.FieldDefs.Create(Sqlite3);
  for i:= 0 to SQLite3_Old.Fields.Count - 1 do
  with Sqlite3.FieldDefs do
  begin
    Add(SQLite3_Old.Fields.Fields[i].FieldName,
    SQLite3_Old.Fields.Fields[i].DataType,
    SQLite3_Old.Fields.Fields[i].Size);
  end;
  Sqlite3.CreateTable(Table_Name);
  // копирование данных
  SQLite3_Old.First;
  Sqlite3.Open;
  while not SQLite3_Old.EOF do
  begin
    Sqlite3.Append;
    for i:= 0 to SQLite3_Old.Fields.Count - 1 do
    begin
      Sqlite3.Fields.Fields[i].Value:= SQLite3_Old.Fields.Fields[i].Value;
    end;
    SQLite3_Old.Next;
  end;


Добавлено спустя 12 часов 39 минут 26 секунд:
Сделал!
Чтобы указать с какой таблицей надо работать необходимо:

Код: Выделить всё

Sqlite3.SQL:= 'select * from ' + Table_Name;
Ответить