C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
"Фильтр по выделенному" как в ACCESS, Подскажите как его сделать!!!
maripossa
Отправлено: 28.11.2006, 22:52


Ученик-кочегар

Группа: Участник
Сообщений: 8



Необходимо выбрать из таблицы записи соответствующие значению на выделенной ячейке определённого поля. А потом из результата выбрать ещё значения , например из другого поля и т.д. Т.е. фильтр не не из всей таблицы, а из результата предыдущего фильтра.

Как это можно реализовать?

Отредактировано maripossa — 28.11.2006, 22:56
AVC
Отправлено: 29.11.2006, 09:45


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE
Как это можно реализовать?

Выборками (select'ами). При работе с SQL лучше "забыть" что можно работать с таблицами и фильтрами.
maripossa
Отправлено: 30.11.2006, 23:00


Ученик-кочегар

Группа: Участник
Сообщений: 8



Всем пасиба!!! Очень помогли!!!

Вот код (кому интересно), сам допетрил. Как говорится, обманул сам себя. Вроде багов нет, но может можно как-то по-проще сделать. Работает даже лучше чем в ACCESSе.

/// ---------------------------------------------------------------------------
/// переделанный код из Дельфи, т.к на нем и пишу;
/*
SL — это переменная класса TStringList;
Изначально, создаю её вместе с загрузкой программы(Form->Create);
и первая строка в переменной должна быть = SL->ADD(Select * from (Название таблицы /*без скобок*/) Where );
Освобождаю (SL->Free;) при закрытии программы, или когда это необходимо ;*/

//-----------Реакция, например, на нажатие кнопки-----------------------

AnsiString QFieldName,QFieldValue,MySQL,S,TempStr;
Int i,Res;
Bool b = false;

QFieldName=DBGridEh1->SelectedField->FieldName; //caption выделенной колонки (DBGidEh коммпонент от www.EhLib.com)
QFieldValue=DBGridEh1->SelectedField->AsString;//текст ячейки в выделенной колонки (DBGidEh коммпонент от www.EhLib.com)

if QFieldValue!="" {/*Если выбранное зачение не пуcтое */
TempStr="["+QFieldName+"]"+ "Like \"+QFieldValue+%\" and "; // могу ошибаться в синтаксисе — должна быть строка типа — [название столбца] like "выделенное значение%" // %-любые символы после выделенного значения
}
if QFieldValue=""{ /*если выбранное зачение пустое*/
TempStr="["+QFieldName+"]"+ "IS NULL OR ["+QFieldName+"] = \'\' ")+" and "; // могу ошибаться в синтаксисе — должна быть строка типа — ([название столбца] IS NULL OR like "")
}

for (i=0; i {
S=SL->Strings[i];
Res = StrComp(S/*переменная должна быть указателем на Char*/,TempStr/*переменная должна быть указателем на Char*/);
if Res = 0 {
B =True;
}
}

if b=false { // если нет повторяющихся строк, то
SL->Add(TempStr);
}

MySQL=Copy(SL.Text,1,length(SL.Text)-6);//это формирование строки запроса //функция "Copy"-это паскаль, т.е копирование строки (SL.Text) без последних 5 байт; В С++ это реализуется как-то по-другому.

///----------------------------------выполнение запроса---------------------------
Query1->Active=false;
Query1->SQL->Clear;
Query1->SQL->Add(MySQL);
Query1->ExecSQL;
OQuery1->Active=true;
///----------------------------------------------------------------------------------------

Отредактировано maripossa — 30.11.2006, 23:28
AVC
Отправлено: 01.12.2006, 09:53


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE

но может можно как-то по-проще сделать


Например так (для полей строкового типа)
CODE

// В Query1->SQL->Text когда то было записано (разгон)
// Query1->SQL->Text = "Select * From бла-бла-бла Where 1 = 1 ";
TField *fld = Grid->SelectedField;
if (!fld) return;
AnsiString QFieldName = fld->FieldName;
AnsiString QFieldValue = fld->AsString.Trim();

AnsiString sqltext = Query1->SQL->Text
+ " and (QFieldName + " like('" + QFieldValue + "%')";
if (QFieldValue.IsEmpty()) sqltext += " or "+ QFieldName + " is Null";

Query1->Active=false;
Query1->SQL->Text = sqltext + ")";
Query1->Active=true;

Это статический запрос. В больших базах так лучше не делать а использовать параметризованные запросы. Но это зависит от сложности и частоты использования запроса.
BadMan
Отправлено: 02.12.2006, 13:11


Дежурный стрелочник

Группа: Участник
Сообщений: 37



Меня на форуме несколько раз критиковали за подобный подход — типа большая нагрузка на сеть и сервер при большом объеме выборки.
Всегда предлагалось пересортировку и перефильтрацию делать на клиентской машине без отправки повторных запросов на сервер...

Если выборка большая — то наверное так делать действительно не стоит.
maripossa
Отправлено: 05.12.2006, 00:11


Ученик-кочегар

Группа: Участник
Сообщений: 8



AVC пасибо за ответ! Но, что значит "параметризованный запрос"? Например, запрос (по выделенному полю столбца) из файла базы ACCESS, объемом 800 тыс строк, выполняестя тоже очень долго! Значит алгоритм релизован примерно такой-же!?

to BadMan:
QUOTE
Если выборка большая

Что значит, "выборка большая"? Выборка — это результат запроса, в большенстве случаев это SQL-запрос .
В моём случае запрос форимируется для всей базы, в зависимости от предыдущего (т.е. запрос выполняется каждый раз из всей базы одной сторкой).

to AVC:
У меня есть мысль: Что если результат первой выборки можно как-то переносить в другую, промежуточную таблицу, а последующий запрос делать уже из неё и т.д. Может это увеличит скорость выполнения запроса?!

Отредактировано maripossa — 05.12.2006, 00:57
olegenty
Отправлено: 05.12.2006, 07:31


Ветеран

Группа: Модератор
Сообщений: 2412



это называется работа с клиентским набором данных. см. в сторону TClientDataSet/TMemTableEh/etc...

т.е. если по результатам первой выборки на клиенте уже есть все данные, перезапросов можно не делать. одно но: результат первой выборки не должен превышать единиц сотен — единиц тысяч записей.
AVC
Отправлено: 05.12.2006, 10:11


Ветеран

Группа: Модератор
Сообщений: 1583



Под размером выборки обычно подразумевается мощность результата (размер строки и их число). Я предпочитаю ограничивать размер на сервере еще на ранних этапах и получать результат минимально необходимого размера.

Параметризованный это запрос имеющий в тексте запроса параметры.
Например Select * From aaa Where field1 = :prm1.

По поводу "результат первой выборки можно как-то переносить в другую, промежуточную таблицу" — делать конечно можно, но если на сервере — то в очень не большом числе случаев. Так как при работе на сервере возникает несколько вопросов: кто потом это чистит (решение temporary table) и сколько нужно одновременно пользователей выполнющих такую детализацию что бы "завалить" сервер.

Вариант — вытащить все не клиента и там фильтровать. Ограничения указал olegenty.

Я, обычно, сначала опрашиваю параметры предлагая пользователю максимально определиться что ему нужно а потом отдаю запрос серверу. Как показывает практика при визуальном контроле человек более 1-2 сотен записей не воспринимает, а из этих внимательнопросматриваются только первые десятки.

QUOTE
запрос (по выделенному полю столбца) из файла базы ACCESS, объемом 800 тыс строк, выполняестя тоже очень долго!

На время выполнения запроса могут повлиять "правильные" индексы и прочие настройки базы. И вообще access это не та система от которой можно ждать рекордов. smile.gif

2BadMan
Я считаю что нагрузка на сеть не должна учитываться. Сеть должна быть такой, что бы это не было для неё нагрузкой тем более в варианте раннего ограничения выборки. А вот нагрузка на сервер — это уже существенней. Поэтому и нужно отказываться от динамической генерации текста запроса и использовать параметризацию. Но, обратно же, все зависит от частоты и сложности.
Почти как подписывается Asher "Это мое мнение и я с ним согласен" biggrin.gif
olegenty
Отправлено: 05.12.2006, 11:44


Ветеран

Группа: Модератор
Сообщений: 2412



в моём случае записей единицы-десятки десятков. например, пользователь захотел увидеть спецификацию некоторого сборочного узла. получил. а вот внутри этой спецификации можно и фильтрануть, если надо, и на сервер я в этом случае не полезу (но я не фильтрую). при этом укладываюсь в собственные ограничения: спецификация одного уровня узла обычно не превышает 50 изделий, реже — 100. а в этом случае пользователям как бы даже пофиг на фильтры, поскольку при интересующей их сортировке найти нужную запись визуально труда уже не составляет, а интерфейс фильтрации отъест драгоценное место экрана (при том, что минимум у меня — 1024x768, рекомендуется 1200x1024, на меньших экранах при заданных требованиях заказчика невозможно уместить запрошенное количество информации).

Вернуться в Работа с базами данных в C++Builder