Консультация № 178333
11.05.2010, 10:30
45.00 руб.
0 16 3
Уважаемые эксперты!
Как многократно изменять SQL-запрос в элементе ADOQuery по событию в программе?
Конкретно, по выделению элемента в списке объекта ComboBox изменять имя таблицы в SQL-запросе так, чтобы объект ADOQuery был активен и из DataSource.DataSet взять значения полученные по запросу.
СУБД – SQLServer2005 Express. Среда – Delphi7. Подключение к БД через ODBC.
Мой код:
ADOQuery4.Active:=False;
ADOQuery4.SQL.Clear;
ADOQuery4.SQL.Text:='SELECT B_CODE B_NAME FROM C15';
ADOQuery4.Open;
ADOQuery4.Active:=True;
ADOQuery4.ExecSQL;
Объект ADOQuery выходит из активного состояния. Соответственно из DataSource можно взять только количество записей и первое значение от запроса.

Обсуждение

Неизвестный
11.05.2010, 10:48
общий
victor_kst:
ADOQuery4.Active:=True;
ADOQuery4.ExecSQL;
Этих двух строк не надо

И если B_CODE и B_NAME это имена полей, а не имя и псевдоним, то между ними нужна запятая

И помоему ADOQuery4.SQL.Clear; уже закрывает кверю, так что ADOQuery4.Active:=False; необязателен
Неизвестный
11.05.2010, 11:28
общий
Алексей S:
ADOQuery4.Active:=False;
Поставил ранее, до того как добавил:
ADOQuery4.SQL.Clear;
B_CODE и B_NAME это имена полей.
Согласен, что нужна запятая,
Но все подставляемые таблицы состоят из двух колонок с такими именами, поэтому вместо B_CODE B_NAME стояла * (звезда)
давно
Профессионал
153662
1070
11.05.2010, 12:50
общий
victor_kst:
Попробуйте так
Код:
ADOQuery4.Close;
ADOQuery4.SQL.Clear;
ADOQuery4.SQL.Add('SELECT B_CODE, B_NAME FROM C15');
ADOQuery4.Open;
у меня в программе работает без проблем.
Об авторе:
Мои программы со статусом freeware для Windows на моём сайте jonix.ucoz.ru

Неизвестный
11.05.2010, 15:03
общий
Евгений/Genia007/:
После ответа Алексея, я понял, что зря паникую, криминала у меня нет.
Оставил вот такой код:
ADOQuery4.SQL.Clear;
cmbx2.Clear;
ADOQuery4.SQL.BeginUpdate;
// ADOQuery4.SQL.Text:='SELECT B_CODE, B_NAME FROM C15';
ADOQuery4.SQL.Text:=sql;
ADOQuery4.SQL.EndUpdate;
ADOQuery4.Open;
ADOQuery4.ExecSQL;
Где я понял из ответа Евгения много лишнего и всё заработало.
Как раздать «слонов», я не знаю.
Помогли и Алексей и Евгений. Обоим спасибо.
Как оформить балы за помощь, подскажите.
Тема закрыта. Пока помощь не нужна.
Неизвестный
11.05.2010, 15:07
общий
это ответ
Здравствуйте, victor_kst.
вот небольшой пример..
В общем то, оформлено в виде функции - сделано специально, что бы показать что и как можно (хотя, это далеко не всё).
Можно проще - например использовать Requery() и т.д.
Старайтесь использовать свойство Active для открытия/закрытия набора данных - это безопасный метод.
При Close и Open - если набор данных в противоречивом состоянии (открыт уже а мы вызываем Open...) выскачет ошибка - старайтесь не надеяться на то, что у вас в коде все "хорошо" и ошибок не будет.. Для этого, используется в примере защищенный блок try
Ну и очень полезно отключать на время переключения набора данных от контролов - DisableControl и после его активации включать - EnableControl - это уберет ненужно моргание в таблицах.

ExecSQL используется для выполнения команд, как правило, управляющих запросов, не возвращающих результат.

Приложение:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, DB, ADODB, Grids, DBGrids;

type
TForm1 = class(TForm)
ADOQuery1: TADOQuery;
ComboBox1: TComboBox;
ADOConnection1: TADOConnection;
DataSource1: TDataSource;
Label1: TLabel;
DBGrid1: TDBGrid;
procedure ComboBox1Change(Sender: TObject);
private
{ Private declarations }
public
function RequeryDS(ds:TDataSet; sTbl:String):integer;
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

function TForm1.RequeryDS(ds: TDataSet; sTbl:String): integer;
begin
result := 0;
ds.DisableControls; // что бы не моргало на время переключения
ds.Active := false;
try
if not ds.ClassNameIs('TADOQuery') then exit; // если это не TADOQuery - выходим
TADOQuery(ds).SQL.Clear;
TADOQuery(ds).SQL.Text := Format('SELECT * FROM %s',[sTbl]);
ds.Active := true; // лучше использовать защищенный (безопасный) метод свойства Active чем Open
result := ds.RecordCount;
finally
ds.EnableControls; // в любом случае вернем управление - выполнять обязательно, иначе так ничего и не отабразится
end;
end;

procedure TForm1.ComboBox1Change(Sender: TObject);
begin
Label1.Caption := Format('всего записей: %d',[RequeryDS(ADOQuery1, ComboBox1.Text)]);
end;

end.
5
Неизвестный
11.05.2010, 15:12
общий
Цитата: 329250
После ответа Алексея, я понял, что зря паникую, криминала у меня нет.

есть
Код:
ADOQuery4.SQL.BeginUpdate;
ADOQuery4.SQL.EndUpdate;
ADOQuery4.ExecSQL;

это не просто лишнее, а и крайне не желательное.
а вот
ADOQuery4.SQL.Text:='SELECT B_CODE, B_NAME FROM C15';
вполне нормально
Неизвестный
11.05.2010, 15:28
общий
Victor Pyrlik:
Для меня тоже оказалось странным, какие выводы были сделаны из моего ответа ) Но раз он помог, то в ответы его и помещаю
Неизвестный
11.05.2010, 15:28
общий
это ответ
Здравствуйте, victor_kst.

ADOQuery4.Active:=True;
ADOQuery4.ExecSQL;
Этих двух строк не надо

И если B_CODE и B_NAME это имена полей, а не имя и псевдоним, то между ними нужна запятая

И помоему ADOQuery4.SQL.Clear; уже закрывает кверю, так что ADOQuery4.Active:=False; необязателен
5
Спасибо!
Неизвестный
11.05.2010, 15:37
общий
Victor Pyrlik:
Спасибо за совет проверю. Пришлите ответ с формой для оценки.
Неизвестный
11.05.2010, 15:39
общий
Цитата: 252413
И помоему ADOQuery4.SQL.Clear; уже закрывает кверю, так что ADOQuery4.Active:=False; необязателен

Надеятся что "вроде должно" не стоит. К тому же, в реальных задачах часто надо при закрытии явно проверять - а не находится ли нбор данных в состоянии изменения..
например:

Код:
procedure TForm1.ADOQuery1AfterClose(DataSet: TDataSet);
begin
if DataSet.State in [dsEdit, dsInsert] then
begin
if MessageBox(GetActiveWindow,'Есть не сохраненные данные! сохранит?',PChar(Caption),MB_ICONQUESTION+MB_YESNO) = IDYES then
DataSet.Post
else
DataSet.Cancel;
end;
end;

Так что, "вроде" не катит
Неизвестный
11.05.2010, 15:40
общий
Евгений/Genia007/:
Пришлите ответ с формой для оценки.
Неизвестный
11.05.2010, 15:44
общий
У меня нет вашей базы - сделал тестовую. Следовательно, не заработает, пока не поправите.
если хотите - вот URL >>test_sql_mssql.rar

[offtop]это работает [/offtop]
давно
Профессионал
153662
1070
11.05.2010, 15:48
общий
это ответ
Здравствуйте, victor_kst.
Могу предложить следующее решение:
Код:
ADOQuery4.Close;
ADOQuery4.SQL.Clear;
ADOQuery4.SQL.Add('SELECT B_CODE, B_NAME FROM C15');
ADOQuery4.Open;
у меня в программе работает без проблем.
5
Об авторе:
Мои программы со статусом freeware для Windows на моём сайте jonix.ucoz.ru

Неизвестный
11.05.2010, 15:53
общий
Victor Pyrlik:
Какая разница, если SQL.Clear на открытом наборе и так вызовет обработчик AfterClose :)

И почему after, а не before?
Неизвестный
11.05.2010, 15:57
общий
Цитата: 252413
И почему after, а не before?

это просто пример. В обработчике закрытия это писать не есть хорошо вообще.
Неизвестный
11.05.2010, 15:59
общий
Victor Pyrlik:
before и есть "до" :)
Форма ответа