TSQLQuery + MySQL

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

Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

TSQLQuery + MySQL

Сообщение VirtUX »

Делаю запрос

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

select `name`,`count`,`place`,`procearned`,`period_to`,`numbercar`,`vincode`,`numberpasp`,`year_make`,`maker`,`vladeler`,`datedocto`,`datedoctoend` from cars

в консоли показывает все 51 запись. TSQLQuery возвращает только 10! В чем может быть проблема?
Как работает запрос:

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

function TDBConnect.DoAnySQL(SQL: TStringList): integer;
var
  i, fi, fc: integer;
  ss: string;
begin

  if SQL = nil
  then begin
    Result := -1;
    exit;
  end;

  fSQLQuery.sql.Text := SQL.Text;
  fSQLQuery.Open;
  Result := fSQLQuery.RecordCount;
  if Result > 0
  then begin
    SQL.Clear;
    fc := pred(fSQLQuery.FieldCount);
    for i := 1 to Result
    do begin

      ss := '';

      for fi := 0 to fc do ss += fSQLQuery.Fields[fi].AsString + #1;

      Delete(ss, Length(ss), 1);
      SQL.Append(ss);
      fSQLQuery.Next;

    end;
  end;

  fSQLQuery.Close;

end;       


Добавлено спустя 43 минуты 53 секунды:
И еще. В этой же таблице пытаюсь обновить запись

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

function TFormDirectorEditCar.DoEdit: boolean;
begin

  Result := false;

  if ComboBoxPlaces.ItemIndex < 0 then
  begin
    ShowMessage('Не выбрано место пребывания!');
    exit;
  end;

  ClientConn.Connect.ExecAnySQL('update cars set `count`='+#39+IntToStr(SpinEditKolvo.Value)+#39+
                                ',`place`='+#39+ComboBoxPlaces.Text+#39+
                                ',`procearned`='+#39+IntToStr(SpinEditProcZP.Value)+#39+
                                ',`period_to`='+#39+IntToStr(SpinEditPeriod.Value)+#39+
                                ',`numbercar`='+#39+EditGosN.Text+#39+
                                ',`vincode`='+#39+EditVIN.Text+#39+
                                ',`numberpasp`='+#39+EditPasp.Text+#39+
                                ',`year_make`='+#39+IntToStr(SpinEditYOut.Value)+#39+
                                ',`maker`='+#39+EditMaker.Text+#39+
                                ',`vladeler`='+#39+EditVladelec.Text+#39+
                                ',`datedocto`='+#39+DateTimeToStr(DateEditTalonDate.Date)+#39+
                                ',`datedoctoend`='+#39+DateTimeToStr(DateEditTalonTo.Date)+#39+
                                ' where `name`='+#39+EditCar.Text+#39+
                                ' limit 1');


  UpdateGrid;

  Result := true;

end;                   

В таблице обновляется. Т.е.

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

procedure TFormDirectorEditCar.UpdateGrid;
var
  cou, i, ci: integer;
  sl: TStringList;
  nowS: string;
begin

  { Очистили таблицу }
  StringGrid1.RowCount:=1;

  sl := TStringList.Create;

  sl.Text:= 'select `name`,`count`,`place`,`procearned`,`period_to`,`numbercar`,`vincode`,`numberpasp`,`year_make`,`maker`,`vladeler`,`datedocto`,`datedoctoend` from cars';
  cou := ClientConn.Connect.DoAnySQL(sl);

  if cou > 0 then
  begin

     StringGrid1.RowCount:= succ(cou);
     for i := 1 to cou
     do begin
        nowS:= sl[pred(i)];
        for ci := 0 to 12
            do StringGrid1.Cells[ci, i] := LSGet(nowS, succ(ci));
     end;

  end;

  sl.Free;

end; 

я вижу, что данные обновились. Но реально, они остаются прежними. TSQLQuery не связан DB-компанентами. Я его использую для простых запросов к MySQL.

Добавлено спустя 25 минут 30 секунд:
С количеством записей разобрался. За это отвечает параметр "PacketRecords". Но возник другой вопрос: как загрузить, скажем, 1000 записей, если "PacketRecords" равен 100?
sign
энтузиаст
Сообщения: 1131
Зарегистрирован: 30.08.2009 09:20:53

Сообщение sign »

Полагаться на количество записей?
Никогда на такое не шёл и не дай бог.

Универсальное, непробиваемое и вечное:

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

fSQLQuery.Open;
while not fSQLQuery.EOF do begin
   ...
  fSQLQuery.Next;
end;


Добавлено спустя 3 минуты 25 секунд:
VirtUX писал(а):как загрузить, скажем, 1000 записей,

Ну, так и загружайте эту 1000 записей, а не извращайтесь.

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

SELECT *
  FROM fSQLQuery
  LIMIT 1000


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

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

  qTmp1.Clear;
  qTmp1.SQL.Add('UPDATE cars SET ' +
                ' `count`=:count ' +
                ',`place`=:place ' +
                ',`procearned`=:procearned ' +
                ',`period_to`=:peroid ' +
                ',`numbercar`=:numbercar ' +
                ',`vincode`=:vincode ' +
                ',`numberpasp`=:numberpasp ' +
                ',`year_make`=:year_make ' +
                ',`maker`=:maker ' +
                ',`vladeler`=:vladeler ' +
                ',`datedocto`=:datedocto ' +
                ',`datedoctoend`=:datedoctoend ' +
                ' where `name`=:name ');
  qTmp1.ParamByName('count').AsInteger         := SpinEditKolvo.Value;
  qTmp1.ParamByName('place').AsString          := ComboBoxPlaces.Text;
  qTmp1.ParamByName('procearned').AsInteger    := SpinEditProcZP.Value;
  qTmp1.ParamByName('period_to').AsInteger     := SpinEditPeriod.Value;
  qTmp1.ParamByName('numbercar').AsString      := EditGosN.Text;
  qTmp1.ParamByName('vincode').AsString        := EditVIN.Text;
  qTmp1.ParamByName('numberpasp').AsString     := EditPasp.Text;
  qTmp1.ParamByName('year_make').AsInteger     := SpinEditYOut.Value;
  qTmp1.ParamByName('maker').AsString          := EditMaker.Text;
  qTmp1.ParamByName('vladeler').AsString       := EditVladelec.Text;
  qTmp1.ParamByName('datedocto').AsDateTime    := DateEditTalonDate.Date;
  qTmp1.ParamByName('datedoctoend').AsDateTime := DateEditTalonTo.Date;
  qTmp1.ParamByName('name').AsString           := EditCar.Text;
  qTmp1.ExecSQL;
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

sign писал(а):Универсальное, непробиваемое и вечное:

Код: Выделить всё
fSQLQuery.Open;
while not fSQLQuery.EOF do begin
...
fSQLQuery.Next;
end;


Работет :)
Сделал так:

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

fSQLQuery.sql.Text := SQL.Text;
  fSQLQuery.Open;
  fSQLQuery.Last;
  Result := fSQLQuery.RecordCount;
  fSQLQuery.First;
  if Result > 0
  then begin
    SQL.Clear;
    fc := pred(fSQLQuery.FieldCount);
    while not fSQLQuery.EOF
    do begin

      ss := '';

      for fi := 0 to fc do ss += fSQLQuery.Fields[fi].AsString + #1;

      Delete(ss, Length(ss), 1);
      SQL.Append(ss);
      fSQLQuery.Next;

    end;
  end;

  fSQLQuery.Close;     

Спасибо!
Добавлено спустя 1 минуту 41 секунду:
sign писал(а):Пользуйтесь для обновления простым, проверенным методом:

Скажите: а что у Вас изменилось, в отличие от моего способа?.. Какая разница как формировать запрос?

Добавлено спустя 1 час 16 минут 9 секунд:
Написал отдельную процедуру для обновления данных:

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

procedure TDBConnect.UpdateSQL(SQL: string);
begin

  if SQL = '' then exit;

  fSQLQuery.UpdateSQL.Text := SQL;
  fSQLQuery.Open;
  fSQLQuery.Edit;
  fSQLQuery.Post;
  fSQLQuery.ApplyUpdates;

  fSQLQuery.Close;
  fSQLTransaction.Commit;

end;

Так работает :)

Добавлено спустя 10 минут 4 секунды:
Или так:

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

procedure TDBConnect.UpdateSQL(SQL: string);
begin

  if SQL = '' then exit;

  fSQLQuery.SQL.Text := SQL;
  fSQLQuery.ExecSQL;
  fSQLQuery.Close;
  fSQLTransaction.Commit;

end; 

Тоже работает
sign
энтузиаст
Сообщения: 1131
Зарегистрирован: 30.08.2009 09:20:53

Сообщение sign »

VirtUX писал(а):Скажите: а что у Вас изменилось, в отличие от моего способа?.. Какая разница как формировать запрос?

Я раньше тоже так думал, пока пару раз тэйблом об фэйс не случилось.
Мой способ гарантирует приведение данных во внутренний формат.
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

Дабы не плодить новую тему, пушу тут.
После обновления MariaDB стал получать ошибку:
TMySQL56Connection can not work with the installed MySQL client version: Expected (5.6), got (10.0.12-MariaDB).

устанавливал клиента 5.6 - не помогает. MariaDB внутри поддерживает и 5,5 и 5,6 вроде как... Что изменилось в этой Машке?
Аватара пользователя
Максим
энтузиаст
Сообщения: 599
Зарегистрирован: 27.07.2007 01:51:43
Откуда: Москва

Сообщение Максим »

Версию они поменяли. Пишите в багтрекер FPC.
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

Аватара пользователя
Максим
энтузиаст
Сообщения: 599
Зарегистрирован: 27.07.2007 01:51:43
Откуда: Москва

Сообщение Максим »

Спасибо. Lazarus тут не при делах, переместил в раздел FPC.
Ism
энтузиаст
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Сообщение Ism »

У TSQLQuery есть свойство SQLQuery1.PacketRecords равное 10 , то есть минимум строк получаемых при открытии
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

Пока разработчики решают как свести MariaDB 10.0.X с MySQL 5.X по версиям...
Решение для фанатов роллинг-релиза openSuSE Factory от 16.08.2014 и выше (а так же для всех у кого MariaDB 10.0.X):
1. Проверяем наличие, и при отсутствии устанавливаем пакет libmysql56client18.
2. Ищем в /usr/lib64/ симлинк libmysqlclient.so.18 на libmysqlclient.so.18.0.0 (это из пакета libmysqlclient18). И если находим его, то удаляем.
3. Создаем нужный симлинк на библиотеку /usr/lib64/libmysql56client.so.18.1.0 или на ее имеющийся симлинк /usr/lib64/libmysql56client.so.18 (я делаю на ее симлинк):

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

ln -s /usr/lib64/libmysql56client.so.18 /usr/lib64/libmysqlclient.so.18

Готово.
Т.о. мы заменяем симлинк на библиотеку от MariaDB, на симлинк MySQL 5.6.
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

Всплыла неприятность в виде потери коннекта с БД, при долгом отсутствии запросов.
Устанавливаю соединение в классе-коннекторе один раз при старте программы/сервера таким образом:

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

constructor UFMySQLConnector.Create(nameDB, host, login, passwd: string);
begin
  fSQLQuery := TSQLQuery.Create(nil);
  fSQLTransaction := TSQLTransaction.Create(nil);

  fMySQLConnection := TMySQL55Connection.Create(nil);

  fMySQLConnection.Transaction := fSQLTransaction;
  fSQLTransaction.DataBase := fMySQLConnection;
  fSQLQuery.DataBase := fMySQLConnection;
  fSQLQuery.Transaction := fSQLTransaction;

  fMySQLConnection.HostName := host;
  fMySQLConnection.UserName := login;
  fMySQLConnection.Password := passwd;
  fMySQLConnection.DatabaseName := nameDB;

  fSQLTransaction.Active:= true;
  if not fMySQLConnection.Connected then fMySQLConnection.Open;
  fSQLQuery.Close;
  fSQLQuery.ParseSQL:= false;
  fSQLQuery.ReadOnly:= False;
  fSQLQuery.UpdateMode:= upWhereAll;
  ExecAnySQL('SET NAMES utf8'); // Это выполнение запроса внутри этого класса
end;         

По закрытии программы/сервера в деструкторе класса-коннектора уничтожаю:

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

destructor UFMySQLConnector.Destroy;
begin
  fMySQLConnection.Free;
  fSQLTransaction.Free;
  fSQLQuery.Free;

  inherited Destroy;
end;   

Можно вынести в отдельные процедуры весь этот код коннекта/дисконнекта и дергать их при отсутствии связи. Но...
1. Что конкретно отвечает за установку и поддержку связи с MySQL? Или: что нужно передёрнуть, чтоб связь возобновилась?
2. Каким образом можно узнать об отсутствии связи? В данный момент я узнаю об этом, когда не получаю ответа на запрос. Но может есть параметр-флаг отвечающий за наличие коннекта?
Ism
энтузиаст
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Сообщение Ism »

У mysql есть опция реконнекта
Попробуйте в параметрах соединения MYSQL_OPT_RECONNECT=1
Но надо проверять, параметр может быть проигнорирован
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

Нарыл следующее:
TSQLConnection.Connected
Is a connection to the server active or not

Description

Connected indicates whether a connection to the server is active or not. No queries to this server can be activated as long as the value is False

Setting the property to True will attempt a connection to the database DatabaseName on host HostName using the credentials specified in UserName and Password. If the connection or authentication fails, an exception is raised. This has the same effect as calling Open.

Setting the property to False will close the connection to the database. All datasets connected to the database will be closed, all transactions will be closed as well. This has the same effect as calling Close

и:
TSQLConnection.KeepConnection
Attempt to keep the connection open once it is established.

Description

KeepConnection can be used to attempt to keep the connection open once it is established. This property is currently not implemented.


Т.е.: при начальном подключении устанавливаем:

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

fMySQLConnection.KeepConnection := true;

и надеемся, что соединение будет поддержано надлежащим образом. НО! При каждом вызове процедуры отправки запроса на сервер, внутри нее делаем проверку:

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

if not fMySQLConnection.Connected then fMySQLConnection.Open; 


Добавлено спустя 49 минут 36 секунд:
Оказалось, что fMySQLConnection.Connected остается в true даже при обрыве связи. И после восстановления связи ошибка соединения с БД не исчезает. Выкрутился пока так:

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

try
    fSQLQuery.Open;
  except
    fMySQLConnection.Close(true);
    try
      fMySQLConnection.Open;
      fSQLQuery.Open;
    except
      Result := -2;  { Сообщение об ошибке }
      Exit;
    end;
  end;

это в процедуре, выполняющей простой запрос на выборку данных.
Соответственно в процедуре внесения изменений:

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

try
    fSQLQuery.ExecSQL;
  except
    fMySQLConnection.Close(true);
    try
      fMySQLConnection.Open;
      fSQLQuery.ExecSQL;
    except
      Result := -2;
      Exit;
    end;
  end; 
Ism
энтузиаст
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Сообщение Ism »

Может лучше это настроить http://dev.mysql.com/doc/connector-pyth ... -ping.html
По идее если включить пинг в клиентской библиотеке, она будет проверять соединение и переподключаться
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

Я думаю, что лучше делать проверку при отправке запроса. Т.к.: нет запроса, значит нам по... до состояния подключения, и никого не напрягаем. Т.к.: во время отправки запроса, пинг мог быть еще не выполнен, а соединение уже отсутствовать; или уменьшать таймаут пинга, что вызовет не нужный напряг, да и не гарантирует наличие соединения во время отправки запроса в любом случае.
ИМХО.
Ответить