Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Web программирование > SQL, базы данных
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 06.10.2011, 09:04   #1
Sasha_S
Пользователь
 
Регистрация: 28.04.2011
Сообщений: 16
По умолчанию Попарное сопоставление строк таблицы

Подскажите, пожалуйста, реально ли решить на SQL следующую задачу.

В таблице есть целочисленные поля X и Y, в которых хранятся координаты точек, образующих границу некоторой области. Каждому значению X соответствует не больше двух значений Y.
Нужно найти максимальную разность по Y точек с одним значением X, и по возможности сами значения X и Y этих точек. То есть, длину самой широкой по Y части области, и где это происходит.
Я представляю себе это так:
1) перебирая все имеющиеся в таблице значения X = X0:
1.1) выбрать все строки с X, близким к X0;
1.2) перебрать все возможные сочетания этих строк и найти для каждого из них разность по Y;
1.3) найти максимальную разность и значения Y, ее образующие (и куда-то, как я понимаю, все это записать, возможно, в новую таблицу)
2) найти максимальную по новой таблице разность, соответствующие ей X и Y и передать в программу.

Какую часть всего этого можно выполнить с помощью SQL? То есть, как это сделать, используя SQL по максимуму? Меня особенно интересует пункт 1.2. Реально ли вообще средствами SQL выполнить такое попарное сравнение строк (может, новую таблицу как-то построить со всеми возможными сочетаниями?), и как это сделать? Если нужно: база данных Access, среда программирования Delphi.

Последний раз редактировалось Sasha_S; 06.10.2011 в 09:15.
Sasha_S вне форума Ответить с цитированием
Старый 06.10.2011, 09:28   #2
evg_m
Старожил
 
Регистрация: 20.04.2008
Сообщений: 5,526
По умолчанию

Код:
select top 1 //только первая запись
max(Y) - min(Y) as Delta, max(Y) as Y2, min(Y) as Y1, X
from tbl group by X
order by 1 desc // из упорядоченных от максимальных по первому полю результаттов  т.е. max(Y) - min(Y)
программа — запись алгоритма на языке понятном транслятору

Последний раз редактировалось evg_m; 06.10.2011 в 09:33.
evg_m на форуме Ответить с цитированием
Старый 06.10.2011, 11:31   #3
Sasha_S
Пользователь
 
Регистрация: 28.04.2011
Сообщений: 16
По умолчанию

evg_m, большое спасибо! Оказывается, это намного проще, чем мне сначала представлялось - пока не умею думать на языке запросов
А можно сделать так, чтобы GROUP BY выполнялось не точно по значению X, а по X плюс-минус некоторое значение? На случай, если максимум Delta должен быть в точке, например, с X = 6, но в таблице есть только (6, 1), (5, 10) и (7,10)?
Sasha_S вне форума Ответить с цитированием
Старый 07.10.2011, 10:21   #4
evg_m
Старожил
 
Регистрация: 20.04.2008
Сообщений: 5,526
По умолчанию

можно попробовать сначала такой запрос
Код:
select tbl.X, tbl.Y, tbl1.Y as Y1, tbl2.Y as Y2
from tbl
left join tbl tbl1 on tbl1.X =tbl.X -1
left join tbl tbl2 on tbl2.X =tbl.X +1
затем к нему приделать group By X и посчитать нужные тебе расстояния (примерно так)

Код:
select tbl.X, min(tbl.Y) as minY, min(tbl1.Y) as minY1, min(tbl2.Y) as minY2, 
....  все что нужно по Y из tbl, tbl1. tbl2
from tbl
left join tbl tbl1 on tbl1.X =tbl.X -1
left join tbl tbl2 on tbl2.X =tbl.X +1 
group by X
потом добавить сравнения на поиск максимального из расстояний.
Код:
select tbl.X,  IIF(.....) ....
потом добавить сортировку по этому полю (order by ... )

потом взять первую запись. (top 1)

А можно так.
после того как приделали group by X ( см. выше).
приделываем выбор нужных min(tbl1.Y1) и т.д.
select tbl1.X, IIF(min(tbl1.Y<tbl.Y ...) as bestminY ...........
IIF( ) as BESTmaxY

затем считаем
select X, bestmaxY -bestminY from ( <это называется вложенный запрос здесь пишем то что получилось на предыдущем этапе т.е. select tbl1.X, IIF(min(tbl1.Y<tbl.Y ...) as bestminY ...........
IIF( ) as BESTmaxY
>) as bestdir
order by // сортируем и берем первую.
программа — запись алгоритма на языке понятном транслятору

Последний раз редактировалось evg_m; 07.10.2011 в 10:38.
evg_m на форуме Ответить с цитированием
Старый 09.10.2011, 14:56   #5
Sasha_S
Пользователь
 
Регистрация: 28.04.2011
Сообщений: 16
По умолчанию

Спасибо за подробный ответ! Все получилось и работает.
В процессе составления запроса была такая проблема: когда в таблице нет строк с X-1 (то же самое - с X+1), поле Y1 (соответственно Y2) при LEFT JOIN заполнялось пустыми значениями, и min(tbl1.Y) по нему считался как null, а потом из-за этого null сбивался результат при сравнении его с min(tbl.Y). Поэтому пришлось добавить функцию NZ, которая в Access заменяет null на числовое значение: 10000 (что-то вроде GetMaxInt) или 0. В результате получился следующий объемный код:
Код:
SELECT TOP 1
  Tbl.X,
  MIN(Tbl.Y) AS MinY0,
  IIF(MIN(NZ(Tbl1.Y, 10000)) < MIN(NZ(Tbl2.Y, 10000)), MIN(NZ(Tbl1.Y, 10000)), MIN(NZ(Tbl2.Y, 10000))) AS MinY12,
  IIF(MinY0 < MinY12, MinY0, MinY12) AS BestMinY,
  MAX(Tbl.Y) AS MaxY0,
  IIF(MAX(NZ(Tbl1.Y, 0)) > MAX(NZ(Tbl2.Y, 0)), MAX(NZ(Tbl1.Y, 0)), MAX(NZ(Tbl2.Y, 0))) AS MaxY12,
  IIF(MaxY0 > MaxY12, MaxY0, MaxY12) AS BestMaxY, 
  (BestMaxY - BestMinY) AS Delta
FROM (Tbl LEFT JOIN Tbl AS Tbl1 ON Tbl1.X = Tbl.X-1) LEFT JOIN Tbl AS Tbl2 ON Tbl2.X = Tbl.X+1
GROUP BY Tbl.X
ORDER BY 8 DESC
С помощью вложенного запроса "свернула" его до двух полей в результате: X и Delta, все остальное считается во вложенном. Не знаю, насколько получилось оптимально и красиво (глупый вопрос, наверное: в пределах IIF можно задать какие-нибудь "псевдонимы" для сравниваемых значений, чтобы не повторять MIN(NZ...)?), но вот этот запрос уже работает в Access. И тут возникла досадная проблема с Delphi: ругается на неизвестную функцию NZ. Как я поняла, причина связана с провайдером Jet 4.0 OLE DB. Пришлось еще раз заменить все выражения типа NZ(A, B) на IIF(ISNULL(A), B, A). Помогло.
Sasha_S вне форума Ответить с цитированием
Старый 09.10.2011, 15:44   #6
evg_m
Старожил
 
Регистрация: 20.04.2008
Сообщений: 5,526
По умолчанию

Цитата:
при LEFT JOIN заполнялось пустыми значениями
еще можно попробовать INNER JOIN
программа — запись алгоритма на языке понятном транслятору
evg_m на форуме Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Выборка из таблицы и копирование строк Bromista Microsoft Office Excel 3 01.10.2011 18:00
Сопоставление полей ввода и ячеек таблицы VanHelsing C++ Builder 1 18.08.2011 19:58
Удаление строк из таблицы kity Microsoft Office Access 3 18.11.2010 21:46
Добавление строк в связанные таблицы StIKEG БД в Delphi 4 16.06.2010 11:46
Удаление строк из таблицы kostero Microsoft Office Access 3 19.03.2010 13:51