選擇

2015-08-30 10 views
0

我有一個的MaxMind DB 2個表,GEOIP和geoLOC選擇

然後我有一些10000城市/城鎮的名單,我想lat和每個城市的LNG,以顯示在地圖上

我會避免使用10000次的循環,以獲得詳細信息: 我認爲這是更好地使用T-SQL的IN聲明,把所有的城市名 但問題是,幾乎所有的大城市都有超過1參考,因此我得到一些重複的結果

我試過使用distinc T:

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,而

這是實現這種結果的方式,並且,可以在此解決方案的更多的表演或者可以更好地利用下一次循環?

此表的定義:

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模塊,因爲對於一些城市來說,分辨率是在郵政編碼等級,因此在相同的geoname_ID中也有不同的經緯度和緯度(我們使用的第一個我們發現的可以接受) 但是還有一個問題是興起:西雅圖在GeoName中只出現過1次,但底特律出現了兩次,波士頓出現4次:既然在佐治亞州,弗吉尼亞州,馬薩諸塞州和紐約有一個名爲波士頓的城市,我猜這樣會讓查詢過於複雜:-(

+0

請問您可以發表表格定義和幾行樣品數據。 –

+0

你需要把你的where子句也夾子外: WHERE l.locale_code = '恩' 和country_iso = '美國' 和l.city IN( '西雅圖', '波士頓', '底特律') – theweeknd

回答

1

從我的理解 - 你想每個城市記錄一個拉特長的價值。 請注意,在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') 
+0

是的,正確的,你的解決方案解決了郵政編碼問題..但還有一個問題:同名的城市,但在不同的州: 波士頓例如出席4次(紐約,弗吉尼亞州,馬薩諸塞州,喬治亞州)。 。:-( – Joe

+0

那麼,預期的結果集是什麼?我根據你在問題中發佈的內容進行了分析,例如 - 你想要哪個波士頓?你總是可以將狀態字段添加到select或where子句中。 –

+0

嗯,我需要的是「正確」的波士頓.. 是的,我可以添加一個狀態字段或在where子句中,但不知道如何處理: 我應該把狀態置於IN子句中,如 'IN('seattle ,WA','波士頓,MA','底特律,密歇根州')''但這是不可能的。 也許唯一的解決方案是迭代每個城市的SQL查詢與一個where子句,而不是使用IN語句.. – Joe

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