问题是下面描述的查询是否可以在不求助于过程逻辑的情况下完成,即是否可以单独由 SQL 和 CTE 和窗口函数处理?我正在使用 SQL Server 2012,但问题不仅限于该引擎。
假设我们有一个包含 250,000 行的全国音乐教师数据库:
teacherName, address, city, state, zipcode, geolocation, primaryInstrument
其中geolocation
列是geography::point
具有最佳细分索引的数据类型。
用户想要五位离他最近的吉他老师。如果我们选择任意距离截断值,例如 50 英里,则使用窗口函数的查询性能足够好,这样我们就不会选择所有 250,000 行,然后按距离对它们进行排序并取最近的 5 行。
但是,如果用户选择来自不同文化的乐器,例如西塔琴或乌德琴或巴拉莱卡琴,那么任意 50 英里半径截断可能并不总是成功地包含 5 位教师;在她所在的 50 英里范围内可能没有五位此类乐器的老师。
另外,现在假设我们有一个查询,音乐学院向我们发送了 250 名歌手的名单,这些歌手是来年被学校录取的学生,他们希望我们向他们发送最接近的五位语音教练名单上的每个人,以便这些学生可以在到达校园之前安排接受一些辅导。我们必须扫描教师数据库 250 次(即扫描地理定位索引),因为这些学生都住在全国不同的地方。
所以,我想知道,对于后一个涉及 250 个学生位置列表的查询,是否有可能编写一个递归查询,其中半径开始很小,例如 10 英里,然后每次迭代增加 10 英里,直到是否已达到 100 英里的最大半径或已找到所需的五 (5) 名教师?能不能只针对还没有匹配到所需5名老师的学生?
我认为它不能单独使用 SQL 来完成,必须通过循环和临时表来完成——但也许那是因为我还没有弄清楚如何单独使用 SQL 来完成。
PS primaryInstrument 列也可以减少按距离排序的集合的大小,但为了这个问题,忘记这一点。
编辑:这是一个示例查询。SINGER(提交的)数据集包含一个具有任意半径的列,以将地理结果限制为较小的子集,但如上所述,该半径可能定义一个可能不包含所需数量的圆(其中心点是学生的地理位置)的老师。有时提供的数据集包含数千个地址,而不仅仅是几百个。
select TEACHERSRANKEDBYDISTANCE.* from
(
select STUDENTSANDTEACHERSINRADIUS.*,
rowpos = row_number()
over(partition by
STUDENTSANDTEACHERSINRADIUS.zipcode+STUDENTSANDTEACHERSINRADIUS.streetaddress
order by DistanceInMiles)
from
(
select
SINGER.name,
SINGER.streetaddress,
SINGER.city,
SINGER.state,
SINGER.zipcode,
TEACHERS.name as TEACHERname,
TEACHERS.streetaddress as TEACHERaddress,
TEACHERS.city as TEACHERcity,
TEACHERS.state as TEACHERstate,
TEACHERS.zipcode as TEACHERzip,
TEACHERS.teacherid,
geography::Point(SINGER.lat, SINGER.lon, 4326).STDistance(TEACHERS.geolocation)
/ (1.6 * 1000) as DistanceInMiles
from
SINGER left join TEACHERS
on
( TEACHERS.geolocation).STDistance( geography::Point(SINGER.lat, SINGER.lon, 4326))
< (SINGER.radius * (1.6 * 1000 ))
and TEACHERS.primaryInstrument='voice'
) as STUDENTSANDTEACHERSINRADIUS
) as TEACHERSRANKEDBYDISTANCE
where rowpos < 6 -- closest 5 is an abitrary requirement given to us