[sql] Выбрать ближайщие точки
Для всех - думается мне надо уже писать скрипт.
именно для всех
Наверное я его представлю и в том случае если ROWID нет, но там будет такое извращение, что лучше скрипт написать.
Если в MSAccess есть нечто типа ROWID, то в принципе я себе этот запрос представляю.вот не знаю
Наверное я его представлю и в том случае если ROWID нет, но там будет такое извращение, что лучше скрипт написать.
![](/images/graemlins/confused.gif)
а что делает ROWID (Oracle?)
Я неправ, нужен ROWNUM на самом деле.
принцип запроса можешь описать кратко?)
![](/images/graemlins/smile.gif)
даже не успел почитать)
select t1.id, t2.id from t1, t2
where t2.id in
(select t2.id from t2 as s2
where rownum=1
order by ( (t1.x-s2.x)*(t1.x-s2.x) + (t1.y-s2.y)*(t1.y-s2.y) )
)
union all
<то же самое для rownum=2>
union all
и т.д.
Если эту хрень сделать подзапросом, то ее можно еще и отсортировать по t1.id.
Если у таблиц нет уникального ключа, можно использовать вместо <что-то>.id - (<что-то>.x, <что-то>.y)
Оракл сжуёт это:
select x1,y1,x2,y2 from (
select a.x x1, a.y y1, b.x x2, b.y y2, row_number over (partition by a.x, a.y order by a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y rn from a, b
) where rn <=5
![](/images/graemlins/ooo.gif)
Можно ли средствами SQL составить запросда можно. Причем с использованием только обычных операторов, которые есть в любом SQL-е. Но это будет очень тяжелый запрос. Если еще актульно, то я могу выписать запрос.
Пиши, интересно посмотреть.
Давай!
select a1.x, a1.y, b1.x, b1.y from a a1,b b1
where (a1.x-b1.x)*(a1.x-b1.x)+(a1.y-b1.y)*(a1.y-b1.y) = (
select mina2.x-b2.x)*(a2.x-b2.x)+(a2.y-b2.y)*(a2.y-b2.y r from a a2,b b2
where a2.x=a1.x and a2.y=a1.y
group by a2.x,a2.y
)
union all
select a1.x, a1.y, b1.x, b1.y from a a1,b b1
where (a1.x-b1.x)*(a1.x-b1.x)+(a1.y-b1.y)*(a1.y-b1.y) = (
select minx1-x2)*(x1-x2)+(y1-y2)*(y1-y2 r from (
select a1.x x1, a1.y y1, b1.x x2, b1.y y2 from a a1,b b1
minus
select a1.x x1, a1.y y1, b1.x x2, b1.y y2 from a a1,b b1
where (a1.x-b1.x)*(a1.x-b1.x)+(a1.y-b1.y)*(a1.y-b1.y) = (
select mina2.x-b2.x)*(a2.x-b2.x)+(a2.y-b2.y)*(a2.y-b2.y r from a a2,b b2
where a2.x=a1.x and a2.y=a1.y
group by a2.x,a2.y)
)
where x1=a1.x and y1=a1.y
group by x1,y1
)
union all
select a1.x, a1.y, b1.x, b1.y from a a1,b b1
where (a1.x-b1.x)*(a1.x-b1.x)+(a1.y-b1.y)*(a1.y-b1.y) = (
select minx1-x2)*(x1-x2)+(y1-y2)*(y1-y2 r from (
select a1.x x1, a1.y y1, b1.x x2, b1.y y2 from a a1,b b1
minus
select a1.x x1, a1.y y1, b1.x x2, b1.y y2 from a a1,b b1
where (a1.x-b1.x)*(a1.x-b1.x)+(a1.y-b1.y)*(a1.y-b1.y) = (
select mina2.x-b2.x)*(a2.x-b2.x)+(a2.y-b2.y)*(a2.y-b2.y r from a a2,b b2
where a2.x=a1.x and a2.y=a1.y
group by a2.x,a2.y)
minus
select a1.x x1, a1.y y1, b1.x x2, b1.y y2 from a a1,b b1
where (a1.x-b1.x)*(a1.x-b1.x)+(a1.y-b1.y)*(a1.y-b1.y) = (
select minx1-x2)*(x1-x2)+(y1-y2)*(y1-y2 r from (
select a1.x x1, a1.y y1, b1.x x2, b1.y y2 from a a1,b b1
minus
select a1.x x1, a1.y y1, b1.x x2, b1.y y2 from a a1,b b1
where (a1.x-b1.x)*(a1.x-b1.x)+(a1.y-b1.y)*(a1.y-b1.y) = (
select mina2.x-b2.x)*(a2.x-b2.x)+(a2.y-b2.y)*(a2.y-b2.y r from a a2,b b2
where a2.x=a1.x and a2.y=a1.y
group by a2.x,a2.y)
)
where x1=a1.x and y1=a1.y
group by x1,y1
)
)
where x1=a1.x and y1=a1.y
group by x1,y1
)
и т.д.
![](/images/graemlins/ooo.gif)
![](/images/graemlins/ooo.gif)
![](/images/graemlins/ooo.gif)
Типа того, только он может для каждой точки больше 5 выдать, если несколько точек на одном расстоянии находятся...
minus не везде есть
а где он есть вообще?
На where not exists заменить можно... Access вроде должен прожевать...
The MINUS operator is equivalent to the EXCEPT operator in the ANSI/ISO SQL standard.
точняк, есть такое
CREATE TABLE T1(
x1 float NOT NULL,
y1 float NOT NULL,
CONSTRAINT [PK_T1] PRIMARY KEY
(
x1,
y1
)
)
CREATE TABLE T2(
x2 float NOT NULL,
y2 float NOT NULL,
CONSTRAINT [PK_T2] PRIMARY KEY
(
x2,
y2
)
)
Сам запрос:
SELECT x1, y1, x2, y2
FROM
(
SELECT T1.*, T2.*, (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2) AS r
FROM T1, T2
) V1
WHERE
(
SELECT COUNT (*)
FROM
(
SELECT T1.*, (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2) AS r
FROM T1, T2
) V2
WHERE V1.x1 = V2.x1
AND V1.y1 = V2.y1
AND V1.r <= V2.r
) <= 5
![](/images/graemlins/crazy.gif)
![](/images/graemlins/smirk.gif)
![](/images/graemlins/grin.gif)
CREATE VIEW V1
AS
SELECT T1.*, T2.*, (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2) AS r
FROM T1, T2
---------------------------------------------------------
CREATE VIEW V2
AS
SELECT V1.*,
(
SELECT COUNT (*)
FROM V1 _V2
WHERE V1.x1 = _V2.x1
AND V1.y1 = _V2.y1
AND V1.r > _V2.r
) AS InCircleN,
(
SELECT COUNT (*)
FROM V1 _V2
WHERE V1.x1 = _V2.x1
AND V1.y1 = _V2.y1
AND V1.r = _V2.r
) AS OnCircleN
FROM V1
---------------------------------------------------------
CREATE VIEW V3
AS
SELECT *
FROM V2
WHERE InCircleN < 5 AND InCircleN + OnCircleN > 5
---------------------------------------------------------
SELECT *
FROM V2
WHERE InCircleN + OnCircleN <= 5
UNION ALL
SELECT *
FROM V3
WHERE
(
SELECT COUNT(*)
FROM V3 _V3
WHERE V3.x1 = _V3.x1
AND V3.y1 = _V3.y1
AND V3.r = _V3.r
AND (V3.x2 < _V3.x2 OR (V3.x2 = _V3.x2 AND V3.y2 < _V3.y2
) < 5 - InCircleN
![](/images/graemlins/grin.gif)
маньяк!
но можно проще
![](/images/graemlins/wink.gif)
кстати, не хорошо навешивать PK на x,y - в реальности будет другой PK, да и их уникальности требовать не очень хорошо. Но работать будет, согласен
![](/images/graemlins/smile.gif)
не хорошо навешивать PK на x,y - в реальности будет другой PKиз соображений производительности — да.
да и их уникальности требовать не очень хорошо
если точки идентифицируются своими координатами, то условие уникальности вполне логично, например, места в кинотеатре. Тут надо более детально исследовать предметную область. В первом посте говорилось только о координатах точек, и я не стал выяснять есть ли скрытый идентификатор точки и взял координаты в качестве идентификатора.
скрытый идентификатор, конечно есть, но все точки с одинаковыми наборами равнозначны и должны выводиться
правильный запрос
конечно есть, но все точки с одинаковыми наборами равнозначны и должны выводитьсянаборы это координаты?
что значит равнозначны? в таблице могут быть записи с одинаковыми координатами?
Запрос легко переписывается для любого случая.
![](/images/graemlins/smile.gif)
наборы это координаты?Наборы из двух координат, уникальными не являются
что значит равнозначны? в таблице могут быть записи с одинаковыми координатами?
Запрос легко переписывается для любого случая.
Равнозначны - значит, что если есть 10 точек на одинаковом расстоянии, то они все должны попадать в результат запроса.
10 точек на одинаковом расстоянии, то они все должны попадать в результат запросаэто противоречит изначальной формулировки запроса
запрос, который сможет выдать к каждой записи (точке) из первой таблицы, по 5 ближайших точек из второй
Сформулируй точно какой запрос нужен.
![](/images/graemlins/smile.gif)
SELECT *
FROM
(
SELECT *,
(
SELECT COUNT (*)
FROM
(
SELECT T1.*, T2.*, (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2) AS r
FROM T1, T2
) _V2
WHERE V1.x1 = _V2.x1
AND V1.y1 = _V2.y1
AND V1.r > _V2.r
) AS InCircleN,
(
SELECT COUNT (*)
FROM
(
SELECT T1.*, T2.*, (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2) AS r
FROM T1, T2
) _V2
WHERE V1.x1 = _V2.x1
AND V1.y1 = _V2.y1
AND V1.r >= _V2.r
) AS InOnCircleN
FROM
(
SELECT T1.*, T2.*, (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2) AS r
FROM T1, T2
) V1
) V2
WHERE InOnCircleN <= 5 OR (InOnCircleN > 5 AND InCircleN < 5)
см. выше
но можно прощенапиши свой вариант запроса
по-моему connect by тебе поможет
Это ж вроде чисто Оракловая фича...
напиши свой вариант запроса
SELECT
*
FROM T1, T2 p1
WHERE
(
SELECT COUNT(*)
FROM T2 p2
WHERE
p1.x2-t1.x1)*(p1.x2-t1.x1)+(p1.y2-t1.y1)*(p1.y2-t1.y1) < (p2.x2-t1.x1)*(p2.x2-t1.x1)+(p2.y2-t1.y1)*(p2.y2-t1.y1
OR p1.x2-t1.x1)*(p1.x2-t1.x1)+(p1.y2-t1.y1)*(p1.y2-t1.y1) = (p2.x2-t1.x1)*(p2.x2-t1.x1)+(p2.y2-t1.y1)*(p2.y2-t1.y1)
AND (p1.x2 < p2.x2 OR (p1.x2 = p2.x2 AND (p1.y2 <= p2.y2
) <= 5
![](/user/upload/file153025.jpg)
![](/user/upload/file153026.jpg)
Для пары точек (0,0) (0,0.5) COUNT дает 3, это не то что нам нужно.
![](/images/graemlins/smile.gif)
надо просто поменять все < на > или поменять алиасы p1 и p2 местами.
В данной реализации он возвращает 5 наиболее удаленных точек
![](/images/graemlins/smile.gif)
поменять алиасы p1 и p2 местамитоже не работает:
![](/user/upload/file153153.jpg)
Прошу прощения, я не потестил.
а ты потести, и подумай
![](/images/graemlins/smirk.gif)
![](/images/graemlins/wink.gif)
X1 Y1 X2 Y2
0 0 0 0.5
0 0 1 -1
1 1 0 0.5
1 1 1 1
подобные запросы уже встечались в моей практике, и подход отработан
запостить второй раззапости, плиз, правильный запрос
SELECT
*
FROM T1, T2 p2
WHERE
(
SELECT COUNT(*)
FROM T2 p1
WHERE
p1.x2-t1.x1)*(p1.x2-t1.x1)+(p1.y2-t1.y1)*(p1.y2-t1.y1) < (p2.x2-t1.x1)*(p2.x2-t1.x1)+(p2.y2-t1.y1)*(p2.y2-t1.y1
OR p1.x2-t1.x1)*(p1.x2-t1.x1)+(p1.y2-t1.y1)*(p1.y2-t1.y1) = (p2.x2-t1.x1)*(p2.x2-t1.x1)+(p2.y2-t1.y1)*(p2.y2-t1.y1)
AND (p1.x2 < p2.x2 OR (p1.x2 = p2.x2 AND (p1.y2 <= p2.y2
) <= 2
встечались в моей практике, и подход отработанно тогда почему ты писал
опять будет глюк, если точки равноудалены, но средствами сыкуля, боюсь, этого никак не избежать
![](/images/graemlins/smile.gif)
плохо подумал
а потом хорошо подумал и понял, что подобные задачи я уже решал, хотя и в другом контексте
![](/images/graemlins/smile.gif)
Оставить комментарий
deniz666
Есть аксессовская база с двумя таблицами, в обеих содержатся координаты точек на карте.Можно ли средствами SQL составить запрос, который сможет выдать к каждой записи (точке) из первой таблицы, по 5 ближайших точек из второй? (в смысле x^2+y^2)