从maxmind db中选择

时间:2015-08-30 14:51:25

标签: tsql maxmind

我有一个包含2个表格的maxmind DB,geoIP和geoLOC

然后我列出了大约10000个城镇,我想让每个城市的lat和lng显示在地图上

我会避免使用10000循环来获取详细信息: 我认为最好使用T-SQL的IN语句并将所有城市命名为 但问题是,几乎所有大城市都有超过1个参考,因此我得到了一些重复的结果

我尝试使用distinct:

SELECT l.*
FROM geoloc l 
JOIN geoip i
ON l.geoname_Id = (SELECT TOP 1 i.geoname_id
                   WHERE l.locale_code='en'
                       AND country_iso='US'
                       AND l.city IN ('seattle','boston','detroit'))

但我得到14284结果而不是3,而

这是实现这种结果的方法,并且,这个解决方案可以更好地执行,还是可以更好地使用for next循环?

此处表格定义:

CREATE TABLE dbo.GeoLoc (
geoname_Id bigint NULL,
locale_code nvarchar(5) COLLATE Latin1_General_CI_AS NULL,
continent_code nvarchar(2) COLLATE Latin1_General_CI_AS NULL,
continent_name nvarchar(50) COLLATE Latin1_General_CI_AS NULL,
country_iso nvarchar(2) COLLATE Latin1_General_CI_AS NULL,
country_name nvarchar(100) COLLATE Latin1_General_CI_AS NULL,
sub1_iso nvarchar(100) COLLATE Latin1_General_CI_AS NULL,
sub1_name nvarchar(100) COLLATE Latin1_General_CI_AS NULL,
sub2_iso nvarchar(130) COLLATE Latin1_General_CI_AS NULL,
sub2_name nvarchar(150) COLLATE Latin1_General_CI_AS NULL,
city nvarchar(255) COLLATE Latin1_General_CI_AS NULL,
metro_code nvarchar(100) COLLATE Latin1_General_CI_AS NULL,
time_zone nvarchar(150) COLLATE Latin1_General_CI_AS NULL
)

CREATE TABLE dbo.GeoIP (
sIP bigint NULL,
eIP bigint NULL,
startIp nvarchar(20) COLLATE Latin1_General_CI_AS NULL,
geoname_id bigint NULL,
rc_geonameid nvarchar(30) COLLATE Latin1_General_CI_AS NULL,
rcg nvarchar(20) COLLATE Latin1_General_CI_AS NULL,
isProxy bit NULL,
isSat bit NULL,
postalcode nvarchar(20) COLLATE Latin1_General_CI_AS NULL,
lat nvarchar(20) COLLATE Latin1_General_CI_AS NULL,
lng nvarchar(20) COLLATE Latin1_General_CI_AS NULL
)
INSERT INTO @GeoLoc(geoname_Id,locale_code,country_iso,sub1_iso,city)
VALUES 
(1,'en','US','WA','seattle'),
(2,'en','US','MA','boston'),
(3,'en','US','MI','detroit'),
(4,'en','US','VA','boston'),
(5,'en','US','TX','boston'),
(6,'en','US','WA','Z'),
(7,'en','US','NY','boston'),
(8,'en','US','GA','boston')

INSERT INTO @GeoIP(geoname_id,lat,lng)
VALUES
(1,47.6062,-122.3321),
(1,47.6062,-122.3321),
(1,47.7396,-122.3426),
(1,47.4323,-121.8034),
(1,47.6738,-122.3419),
(1,47.4323,-121.8034),
(1,47.6062,-122.3321),
(2,42.6207,-78.7213),
(2,42.6207,-78.7213),
(2,42.6207,-78.7213),
(2,42.6207,-78.7213),
(3,42.3523,-83.0271),
(3,42.3314,-83.0457),
(3,42.3539,-83.2120),
(3,42.3314,-83.0457),
(3,42.3756,-83.1085)

因此geoIP中的geoname_id不是univoque,因为有许多记录具有相同的geoname_ID(因为有许多IP块被引用到同一个城市,并且因为,对于某些城市,分辨率处于邮政编码级别,因此也有不同的lat和lng使用相同的geoname_ID(对于我们的使用,我们发现的第一个是可以接受的)。 但还有一个问题出现了:GeoName中的西雅图只出现了一次,但是底特律出现了两次而波士顿出现了4次:因为在乔治亚州,弗吉尼亚州,马萨诸塞州和纽约都有一个名叫波士顿的城市。 ,我认为使查询过于复杂: - (

2 个答案:

答案 0 :(得分:1)

根据我的理解 - 您希望每个城市的记录具有lat-long值。 请记住,在MaxMind原始数据中,每个邮政编码每个城市有多个条目。每个都有Lat和Long值。

SELECT GL.geoname_Id, GL.city, LatLong.Lat, LatLong.Long
FROM GeoLoc GL with(NOLOCK)
OUTER APPLY (SELECT Top(1) Lat,Long from GeoIP GI WITH(NOLOCK) WHERE GI.geoname_id = GL.geoname_id order by GI.geoname_id) LatLong
WHERE GL.locale_code = 'en' 
  AND GL.countru_iso = 'US'
  AND GL.city IN ('seattle','boston','detroit')

答案 1 :(得分:0)

我不是100%肯定你的追求,但我希望以下其中一个将是你想要的。

如果没有,请使用以下示例来帮助更好地解释您的问题。 如果你可以根据我的例子给我更好的数据,那将会有很大帮助。也是您想要的结果示例,以及您获得的结果。

DECLARE @GeoLoc TABLE
(
   geoname_Id bigint,   --PK
   locale_code nvarchar(5),
   continent_code nvarchar(2),
   continent_name nvarchar(50),
   country_iso nvarchar(2),
   country_name nvarchar(100),
   sub1_iso nvarchar(100),
   sub1_name nvarchar(100),
   sub2_iso nvarchar(130),
   sub2_name nvarchar(150),
   city nvarchar(255),
   metro_code nvarchar(100),
   time_zone nvarchar(150)
)

INSERT INTO @GeoLoc(geoname_Id,locale_code,country_iso,city)
VALUES 
   (1,'en','US','seattle'),
   (2,'en','US','boston'),
   (3,'en','US','detroit'),
   (4,'en','US','X'),
   (5,'en','US','Y'),
   (6,'en','US','Z') 


DECLARE @GeoIP TABLE
(
   sIP bigint,
   eIP bigint,
   startIp nvarchar(20),
   geoname_id bigint,   --FK
   rc_geonameid nvarchar(30),
   rcg nvarchar(20),
   isProxy bit,
   isSat bit,
   postalcode nvarchar(20),
   lat nvarchar(20),
   lng nvarchar(20)
)

INSERT INTO @GeoIP(geoname_id,lat,lng)
VALUES
   (1,1,2),
   (2,1,2),
   (3,5,6)  


--Each cities location
------------------------------
SELECT      GP.lat,GP.lng,GL.city
FROM            @GeoLoc AS GL
INNER JOIN  @GeoIP AS GP ON GL.geoname_Id = GP.geoname_id
--Filter here WHERE         GL.city IN ('')

--Each location only once and one city name (The last one alphabetically)
------------------------------
SELECT      GP.lat,GP.lng,MAX(GL.city)
FROM            @GeoLoc AS GL
INNER JOIN  @GeoIP AS GP ON GL.geoname_Id = GP.geoname_id
--Filter here WHERE         GL.city IN ('')
GROUP BY        GP.lat,GP.lng

--Each location only once and all city names but only one result per location
------------------------------
SELECT      GP.lat,GP.lng,(SELECT STUFF((SELECT ',' + city FROM @GeoLoc AS GL INNER JOIN @GeoIP AS GP2 ON GL.geoname_Id = GP2.geoname_id WHERE GP.lat = GP2.lat AND GP.lng = GP2.lng ORDER BY GL.city FOR XML PATH('')),1,1,''))
FROM            @GeoIP AS GP
INNER JOIN  @GeoLoc AS GL ON GP.geoname_id = GL.geoname_Id
--Filter here WHERE         GL.city IN ('')
GROUP BY        GP.lat,GP.lng