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


Автор: Матроскин 22.8.2004, 14:56
Дело в том, что я уже месяц делаю программу по японскому морю. Сущность в том, что бы проставить на карте точки и получить отчёт - скорости звука в этих точках на разных глубинах. Но, как вы понимаете, проставить точки на карте в точности в том месте, которому соответствует запись в БД нереально. Поэтому метод простой - подбираем ближайшую существующую точку в БД.
Таблица данных имеет 1'200'000 записей.
Структура:
id
lat - широта
lon - долгота
deep - глубина
velo - скорость звука
be - номер дня в году, с которого началось измерение
ee - -||- в котором закончилось измерение (они все длились ровно месяц)

Т.о. задача такова:
вход: lat_u, lon_u - координаты точки пользователя в морских координатах
Например
lat_u = 43.0
lon_u = 134.0
Выход
lat_u = 43.3
lon_u = 134.34

Вот так господа

Автор: <Spawn> 22.8.2004, 19:28
Код

Type
 TSeaPosition = record
   lat_u, lon_u: Real;
 end;

function GetRealSeaPosition(SeaPosition: TSeapPosition): TSeaPosition;
begin
 {Получаем первую ближайшую}
 Query.SQL.Text := 'SELECT Max(lat) FROM Table WHERE lat <= :lat_u';
 Query.ParamByName('lat_u').AsFloat := SeaPosition.lat_u;
 Query.Open;
 Query.Close;
 
 Result.lat_u := Query.FieldByName('lat').AsFloat;

 {Получаем вторую ближайшею точку}
 Query.SQL.Text := 'SELECT Min(lat) FROM Table WHERE lat >= :lat_u';

 Query.ParamByName('lat_u').AsFloat := SeaPosition.lat_u;
 Query.Open;
 Query.Close;

 {Находим ближаушую точку}
 if (SeaPosition.lat_u - Result.lat_u) > (Query.FieldByName('lat_u').AsFloat - SeaPosition.lat_u) then
   Result.lat_u := SeaPosition.lat_u;

 {тоже самое для lot_n}
end;

{далее где то используешь примерно так}
var
 RealPosition: TSeaPosition;
begin
 RealPosition.lat_u := 43.3;
 RealPosition.lon_u := 134.4;
 RealPosition := GetRealSeaPosition(RealPosition);
 Query.SQL.Text := 'SELECT velo
                                   FROM Table
                                 WHERE lat = :lat_u
                                      AND lon = :lon_u';
 Query.ParamByName('lat_u').AsFloat := RealPosition.lat_u;
 Query.ParamByName('lon_u').AsFloat := RealPostition.lon_u;
 Query.Open;
 Query.Close;
 if not Query.IsEmpty then
   ShowMessage(FloatToStr(Query.FieldByName('velo').AsFloat));
end;


Примерно так - я не проверял это код, но думаю идея понятна. Да, и в функции GetRealSeaPosition нет проверки на случай если точка не будет найдена - учти это.
Добавлено @ 19:33
И еще одно замечание - у тебя 1 200 000 записей в базе. Даже если ты сделаешь индекс по полям lat и lon, то учитывая что проверка идет на больше\меньше, то индесы работать не будут, если я правильно помню одну статью - прийдется тут чего то выдумывать.

Автор: Матроскин 23.8.2004, 15:12
Спасибо, как проверю сразу сообщу.

Автор: Матроскин 24.8.2004, 15:53
Да, работает. Но как тороз-з-з-з-ит! Около 7 секунд одну выборку! Лодку сто раз торпеда потопит, пока эта программа выдаст отчёт. (Шутка) Итого у меня получается 20 выборок.
Тормоззз идёт две минуты.

Автор: <Spawn> 24.8.2004, 23:27
Матроскин Думай чего то с индексами.

Автор: AntonSaburov 25.8.2004, 11:06
Цитата
Думай чего то с индексами.

Или ставь какой-нибудь SQL - они обычно заточены на базы и работают гораздо быстрее, чем локальные базы большого размера. У тебя все-таки более миллиона записей.

Автор: Матроскин 25.8.2004, 15:30
Цитата
Матроскин Думай чего то с индексами.

Всё таки единственный выход, который я вижу это использование индексов. Как только найду решение сразу выложу.

Автор: Матроскин 30.8.2004, 04:00
Мужики оно работает!
Создаём комплексный индекс по полям Lat и Lon.

Table1.IndexName := 'iLatLon';
Table1.FindNearest([SeaPosition.lat_u, SeaPosition.lon_u]);

Ищет в доли секунды

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