我怎样才能“为每个”做到这一点? SQL Server 2008 中的代码不使用游标?

发布于 2024-09-19 18:46:50 字数 1100 浏览 7 评论 0原文

如果可能的话,我希望在不使用 CURSOR 的情况下在 SQL 中执行以下伪代码。

for each zipcode
{
    -- What city is this zipcode in? A zipcode can be in multiple cities, 
    -- but one city area is always way greater that the others.
    -- Eg. 90210 is 96% in the city of Beverly Hills. 
    -- The remaining 4% is that it s in some other fringe cties .. 
    --but only just (some mismatch mapping errors).

    ** grab the city largest shape area which this zip is a part of **
}

现在,我有一些 SQL 可以帮助我们。

-- All zipcodes and each boundary/shapefile.
SELECT ZipCodeId, Boundary FROM ZipCodes -- Boundary is a GEOGRAPHY field type.

To determine if a zipcode boundary is in a city....
SELECT CityId, CityName, 
    City.Boundary.Intersection(@someZipCodeBoundary).STArea() AS Area
FROM Cities
WHERE City.Boundary.Intersects(@someZipCodeBoundary) = 1

并获取交集面积(因为我们想要最高的交集面积,即 TOP(1) ORDER BY Area DESCDISTINCT 与 ORDER BY 之类的东西我们使用 Intersection SQL 方法

注意:IntersectsIntersection 是两种不同的 Sql 方法。

I wish to do the following pseudo-code in SQL without the use of a CURSOR, if possible.

for each zipcode
{
    -- What city is this zipcode in? A zipcode can be in multiple cities, 
    -- but one city area is always way greater that the others.
    -- Eg. 90210 is 96% in the city of Beverly Hills. 
    -- The remaining 4% is that it s in some other fringe cties .. 
    --but only just (some mismatch mapping errors).

    ** grab the city largest shape area which this zip is a part of **
}

Now, I have some SQL to help us out.

-- All zipcodes and each boundary/shapefile.
SELECT ZipCodeId, Boundary FROM ZipCodes -- Boundary is a GEOGRAPHY field type.

To determine if a zipcode boundary is in a city....
SELECT CityId, CityName, 
    City.Boundary.Intersection(@someZipCodeBoundary).STArea() AS Area
FROM Cities
WHERE City.Boundary.Intersects(@someZipCodeBoundary) = 1

and to get the area of intersection (because we want the highest area of intersection ie. TOP(1) ORDER BY Area DESC or a DISTINCT with an ORDER BY sort of thing. We use the Intersection SQL method.

Note: Intersects and Intersection are two different Sql methods.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

喜爱皱眉﹌ 2024-09-26 18:46:57

尝试另一种方法。获取某个地方的人口普查统计数据,并筛选出按相同邮政编码分组的人口最多的城市。

例如,像这个地名词典

Try another approach. Get somewhere a census statistics and filter out cities with maximum population grouped by the same zip code.

Like this Gazetteer thing, for example.

送君千里 2024-09-26 18:46:56

好的 - 明白了;)诀窍是使用 PARTITION BY。当我意识到我以前做过类似的事情时,@In Sane 给了我这个想法:)

所以..我们开始..

SELECT 
    a.CityId, a.Name, b.ZipCodeId, b.Code, a.Boundary.STIntersection(b.Boundary).STArea() AS Area, 
    RANK() OVER (PARTITION BY b.ZipCodeId ORDER BY a.Boundary.STIntersection(b.Boundary).STArea() DESC) AS Area_Rank
FROM 
    Cities a
    INNER JOIN ZipCodes b on a.Boundary.STIntersects(b.Boundary) = 1
    where b.Code = 12010 OR b.Code = 90210


CityId      Name                                                                                                 ZipCodeId   Code                 Area                   Area_Rank
----------- ---------------------------------------------------------------------------------------------------- ----------- -------------------- ---------------------- --------------------
2166        Los Angeles                                                                                          9331        90210                13235413.8430175       1
1686        Beverly Hills                                                                                        9331        90210                10413397.1372613       2
2635        West Hollywood                                                                                       9331        90210                0                      3
14570       Amsterdam                                                                                            29779       12010                15369521.9602067       1
14921       Hagaman                                                                                              29779       12010                1394562.70390667       2
14856       Fort Johnson                                                                                         29779       12010                211058.884834718       3
14651       Broadalbin                                                                                           29779       12010                0                      4

(7 row(s) affected)

所以在这个过滤的例子中(按邮政编码12010或90210过滤),我们可以看到这个邮政编码存在于4个不同的城市/城镇。每个邮政编码可以有一对多结果,然后按区域值排序..但这里的关键是 PARTITION 关键字..它按邮政编码组或分区进行排序。非常时髦:)注意到邮政编码 90210 是如何拥有自己的排名结果的吗?和12010一样吗?

接下来,我们将其设为子查询,然后获取所有 Rank == 1 :)

SELECT CityId, Name, ZipCodeId, Code, Area_Rank
FROM (
SELECT 
    a.CityId, a.Name, b.ZipCodeId, b.Code, a.Boundary.STIntersection(b.Boundary).STArea() AS Area, 
    RANK() OVER (PARTITION BY b.ZipCodeId ORDER BY a.Boundary.STIntersection(b.Boundary).STArea() DESC) AS Area_Rank
FROM 
    Cities a
    INNER JOIN ZipCodes b on a.Boundary.STIntersects(b.Boundary) = 1
    where b.Code = 12010 OR b.Code = 90210
) subQuery
WHERE Area_Rank = 1


CityId      Name                                                                                                 ZipCodeId   Code                 Area_Rank
----------- ---------------------------------------------------------------------------------------------------- ----------- -------------------- --------------------
14570       Amsterdam                                                                                            29779       12010                1
2166        Los Angeles                                                                                          9331        90210                1

(2 row(s) affected)

Sweet as candy :)

旁注:这也表明我的洛杉矶城市形状文件/边界已损坏,因为它与邮政编码 90210 相交太多(我直观地确认了这一点:P)

alt text

Ok - got it ;) The trick was to use a PARTITION BY. @In Sane gave me the idea when I realised I've done something similar, before :)

So .. here we go..

SELECT 
    a.CityId, a.Name, b.ZipCodeId, b.Code, a.Boundary.STIntersection(b.Boundary).STArea() AS Area, 
    RANK() OVER (PARTITION BY b.ZipCodeId ORDER BY a.Boundary.STIntersection(b.Boundary).STArea() DESC) AS Area_Rank
FROM 
    Cities a
    INNER JOIN ZipCodes b on a.Boundary.STIntersects(b.Boundary) = 1
    where b.Code = 12010 OR b.Code = 90210


CityId      Name                                                                                                 ZipCodeId   Code                 Area                   Area_Rank
----------- ---------------------------------------------------------------------------------------------------- ----------- -------------------- ---------------------- --------------------
2166        Los Angeles                                                                                          9331        90210                13235413.8430175       1
1686        Beverly Hills                                                                                        9331        90210                10413397.1372613       2
2635        West Hollywood                                                                                       9331        90210                0                      3
14570       Amsterdam                                                                                            29779       12010                15369521.9602067       1
14921       Hagaman                                                                                              29779       12010                1394562.70390667       2
14856       Fort Johnson                                                                                         29779       12010                211058.884834718       3
14651       Broadalbin                                                                                           29779       12010                0                      4

(7 row(s) affected)

So in this filtered example (Filtered by ZipCode 12010 or 90210), we can see that this zipcode exists in 4 different cities/towns. Each zipcode can have 1 to many results, which are then ordered by the Area value .. but the key here is the PARTITION keyword .. which does this ordering by ZipCode groups or partitions. Very funky :) Notice how the zipcode 90210 has it's own rank results? same with 12010 ?

Next, we make that a subquery, and just grab all the Rank == 1 :)

SELECT CityId, Name, ZipCodeId, Code, Area_Rank
FROM (
SELECT 
    a.CityId, a.Name, b.ZipCodeId, b.Code, a.Boundary.STIntersection(b.Boundary).STArea() AS Area, 
    RANK() OVER (PARTITION BY b.ZipCodeId ORDER BY a.Boundary.STIntersection(b.Boundary).STArea() DESC) AS Area_Rank
FROM 
    Cities a
    INNER JOIN ZipCodes b on a.Boundary.STIntersects(b.Boundary) = 1
    where b.Code = 12010 OR b.Code = 90210
) subQuery
WHERE Area_Rank = 1


CityId      Name                                                                                                 ZipCodeId   Code                 Area_Rank
----------- ---------------------------------------------------------------------------------------------------- ----------- -------------------- --------------------
14570       Amsterdam                                                                                            29779       12010                1
2166        Los Angeles                                                                                          9331        90210                1

(2 row(s) affected)

Sweet as candy :)

Side Note: This also shows me that my Los Angeles city shapefile/boundary is corrupted, because it's intersecting the zipcode 90210 far too much (which I visually confirmed :P)

alt text

胡大本事 2024-09-26 18:46:55

我必须说,我不知道交集/交集是什么或它们的作用,我必须澄清我不理解下面的语法 Boundary.Intersection(@someZipCodeBoundary)。 要么

假设你的这个查询返回与指定的 zipcodeBoundary 相交的所有城市,并且 Area 是它们的相交区域

SELECT 
    CityId, 
    CityName, 
    City.Boundary.Intersection(@someZipCodeBoundary).STArea() AS Area 
FROM 
    Cities 
WHERE 
    City.Boundary.Intersects(@someZipCodeBoundary) = 1 

根据我的理解,drachenstern 上面建议的是使用 MAX 是

SELECT 
    CityId, 
    MAX(City.Boundary.Intersection(@someZipCodeBoundary).STArea()) AS Area
FROM 
    Cities 
WHERE 
    City.Boundary.Intersects(@someZipCodeBoundary) = 1 
GROUP BY CityId

这应该给你具有 MAXIMUM 的 CITYID交叉区域。

I must say that i have no idea about what Intersection / Intersects are or what they do and i must clarify that i dont understand this syntax below Boundary.Intersection(@someZipCodeBoundary). either

Assuming that this query of yours returns all cities which intersect with the zipcodeBoundary specified and Area is their area of intersection,

SELECT 
    CityId, 
    CityName, 
    City.Boundary.Intersection(@someZipCodeBoundary).STArea() AS Area 
FROM 
    Cities 
WHERE 
    City.Boundary.Intersects(@someZipCodeBoundary) = 1 

Based on my understanding, what drachenstern is suggesting above is about using MAX is

SELECT 
    CityId, 
    MAX(City.Boundary.Intersection(@someZipCodeBoundary).STArea()) AS Area
FROM 
    Cities 
WHERE 
    City.Boundary.Intersects(@someZipCodeBoundary) = 1 
GROUP BY CityId

This should give you the CITYID which has the MAXIMUM intersection area.

李白 2024-09-26 18:46:54

Max 可以吗?

Does Max work for that?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文