加入SQL查询 - 无法在IP帮助下为获取国家/地区编写查询

时间:2013-06-21 20:26:50

标签: mysql sql

我有一个访问者列表,其中记录了我的IP。现在,我需要查看每位访客来自哪个国家/地区。

我将此任务分为两部分,首先获取具有唯一登录用户的所有IP,第二部分是搜索具有国家/ IP信息的两个表(来自ip2nation)并获取提供的国家/地区IP

第一部分 - 获取唯一登录的用户的所有IP

SELECT
     a.uid, a.hostname, a.timestamp, 
 COUNT(*) AS times
FROM
  login_activity a
GROUP BY
  a.hostname
ORDER BY
  times desc

这给了我所有过去登录用户的IP(主机名)。工作正常。

第二部分 - 通过输入IP

从两个表中获取国家(两者都有数千条记录)
SELECT 
    c.country
FROM 
    ip2nationCountries c, ip2nation i
WHERE 
    i.ip < INET_ATON(  "157.191.122.36" ) 
AND 
    c.code = i.country

ORDER BY i.ip DESC 
LIMIT 0 , 1

这也很有用。

现在,对于真正的问题。加入这两个查询,从所有登录用户获取国家(而不是IP)。这就是我写的: -

        SELECT
         a.uid, a.hostname, a.timestamp, c.country, 
         COUNT(*) AS times
        FROM
          login_activity a, ip2nationCountries c, ip2nation i
        WHERE
           i.ip < INET_ATON(a.hostname)     
           AND c.code = i.country

        GROUP BY
          a.hostname
        ORDER BY
          times desc;

这有两个问题: -

  • 加载需要很长时间。
  • 它提供了错误的数据(显示每行数千次访问)。
  • 基本上,它显示所有数据都错误。

你能帮我制作这个SQL吗?

以防万一,表格的结构/数据如下: -

表的结构/数据是: -

ip2nation (有很多数据)

(结构)

CREATE TABLE ip2nation (
  ip int(11) unsigned NOT NULL default '0',
  country char(2) NOT NULL default '',
  KEY ip (ip)
);

(数据)

INSERT INTO ip2nation (ip, country) VALUES(0, 'us');
INSERT INTO ip2nation (ip, country) VALUES(687865856, 'za');
INSERT INTO ip2nation (ip, country) VALUES(689963008, 'eg');
INSERT INTO ip2nation (ip, country) VALUES(691011584, 'za');
INSERT INTO ip2nation (ip, country) VALUES(691617792, 'zw');
INSERT INTO ip2nation (ip, country) VALUES(691621888, 'lr');
INSERT INTO ip2nation (ip, country) VALUES(691625984, 'ke');
INSERT INTO ip2nation (ip, country) VALUES(691630080, 'za');
INSERT INTO ip2nation (ip, country) VALUES(691631104, 'gh');
INSERT INTO ip2nation (ip, country) VALUES(691632128, 'ng');
INSERT INTO ip2nation (ip, country) VALUES(691633152, 'zw');
INSERT INTO ip2nation (ip, country) VALUES(691634176, 'za');
INSERT INTO ip2nation (ip, country) VALUES(691650560, 'gh');
INSERT INTO ip2nation (ip, country) VALUES(691666944, 'ng');
INSERT INTO ip2nation (ip, country) VALUES(691732480, 'tz');
INSERT INTO ip2nation (ip, country) VALUES(691798016, 'zm');
INSERT INTO ip2nation (ip, country) VALUES(691863552, 'za');
INSERT INTO ip2nation (ip, country) VALUES(691994624, 'zm');
INSERT INTO ip2nation (ip, country) VALUES(692011008, 'za');
INSERT INTO ip2nation (ip, country) VALUES(692027392, 'mg');
INSERT INTO ip2nation (ip, country) VALUES(692035584, 'ao');
INSERT INTO ip2nation (ip, country) VALUES(692043776, 'na');
INSERT INTO ip2nation (ip, country) VALUES(692060160, 'eg');
INSERT INTO ip2nation (ip, country) VALUES(692191232, 'ci');
INSERT INTO ip2nation (ip, country) VALUES(692207616, 'za');
INSERT INTO ip2nation (ip, country) VALUES(692240384, 'gh');
INSERT INTO ip2nation (ip, country) VALUES(692256768, 'sd');

ip2nationCountries (包含大量数据)

(结构)

CREATE TABLE ip2nationCountries (
  code varchar(4) NOT NULL default '',
  iso_code_2 varchar(2) NOT NULL default '',
  iso_code_3 varchar(3) default '',
  iso_country varchar(255) NOT NULL default '',
  country varchar(255) NOT NULL default '',
  lat float NOT NULL default '0',
  lon float NOT NULL default '0',  
  PRIMARY KEY  (code),
  KEY code (code)
);

(数据)

INSERT INTO ip2nationCountries (code, iso_code_2, iso_code_3, iso_country, country, lat, lon) VALUES('ad', 'AN', 'AND', 'Andorra', 'Andorra', 42.3, 1.3);
INSERT INTO ip2nationCountries (code, iso_code_2, iso_code_3, iso_country, country, lat, lon) VALUES('ae', 'AR', 'ARE', 'United Arab Emirates', 'United Arab Emirates', 24, 54);
INSERT INTO ip2nationCountries (code, iso_code_2, iso_code_3, iso_country, country, lat, lon) VALUES('af', 'AF', 'AFG', 'Afghanistan', 'Afghanistan', 33, 65);
INSERT INTO ip2nationCountries (code, iso_code_2, iso_code_3, iso_country, country, lat, lon) VALUES('ag', 'AT', 'ATG', 'Antigua and Barbuda', 'Antigua and Barbuda', 17.03, -61.48);
INSERT INTO ip2nationCountries (code, iso_code_2, iso_code_3, iso_country, country, lat, lon) VALUES('ai', 'AI', 'AIA', 'Anguilla', 'Anguilla', 18.15, -63.1);
INSERT INTO ip2nationCountries (code, iso_code_2, iso_code_3, iso_country, country, lat, lon) VALUES('al', 'AL', 'ALB', 'Albania', 'Albania', 41, 20);
INSERT INTO ip2nationCountries (code, iso_code_2, iso_code_3, iso_country, country, lat, lon) VALUES('am', 'AR', 'ARM', 'Armenia', 'Armenia', 40, 45);
INSERT INTO ip2nationCountries (code, iso_code_2, iso_code_3, iso_country, country, lat, lon) VALUES('an', 'AN', 'ANT', 'Netherlands Antilles', 'Netherlands Antilles', 12.15, -68.45);
INSERT INTO ip2nationCountries (code, iso_code_2, iso_code_3, iso_country, country, lat, lon) VALUES('ao', 'AG', 'AGO', 'Angola', 'Angola', -12.3, 18.3);
INSERT INTO ip2nationCountries (code, iso_code_2, iso_code_3, iso_country, country, lat, lon) VALUES('aq', 'AT', 'ATA', 'Antarctica', 'Antarctica', -90, 0);
INSERT INTO ip2nationCountries (code, iso_code_2, iso_code_3, iso_country, country, lat, lon) VALUES('ar', 'AR', 'ARG', 'Argentina', 'Argentina', -34, -64);
INSERT INTO ip2nationCountries (code, iso_code_2, iso_code_3, iso_country, country, lat, lon) VALUES('as', 'AS', 'ASM', 'American Samoa', 'American Samoa', -14.2, -170);
INSERT INTO ip2nationCountries (code, iso_code_2, iso_code_3, iso_country, country, lat, lon) VALUES('at', 'AU', 'AUT', 'Austria', 'Austria', 47.2, 13.2);
INSERT INTO ip2nationCountries (code, iso_code_2, iso_code_3, iso_country, country, lat, lon) VALUES('au', 'AU', 'AUS', 'Australia', 'Australia', -27, 133);
INSERT INTO ip2nationCountries (code, iso_code_2, iso_code_3, iso_country, country, lat, lon) VALUES('aw', 'AB', 'ABW', 'Aruba', 'Aruba', 12.3, -69.58);

login_activity

(结构)

CREATE TABLE IF NOT EXISTS `mslop_login_activity` (
  `aid` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'The primary identifier for an activity (session).',
  `uid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'The mslop_users.uid corresponding to a session, or 0 for anonymous user.',
  `host_user_agent` varchar(256) NOT NULL DEFAULT '' COMMENT '$_SERVER["HOST_USER_AGENT"] string. This can be used with get_browser() in PHP.',
  `hostname` varchar(128) NOT NULL DEFAULT '' COMMENT 'The IP address that was used for this session.',
  `timestamp` int(11) NOT NULL DEFAULT '0' COMMENT 'The UNIX timestamp when the session was started.',
  PRIMARY KEY (`aid`),
  KEY `aid` (`aid`),
  KEY `uid` (`uid`),
  KEY `timestamp` (`timestamp`)
);

(数据)

INSERT INTO `mslop_login_activity` (`aid`, `uid`, `host_user_agent`, `hostname`, `timestamp`) VALUES
(1, 3, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:19.0) Gecko/20100101 Firefox/19.0', '172.24.1.143', 1363038356),
(2, 3, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:19.0) Gecko/20100101 Firefox/19.0', '172.24.1.143', 1363038374),
(3, 3, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17', '172.24.1.143', 1363193841),
(4, 3, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17', '172.24.1.143', 1363194789),
(5, 3, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17', '172.24.1.143', 1363197889),
(6, 3, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/536.26.17 (KHTML, like Gecko) Version/6.0.2 Safari/536.26.17', '172.24.1.143', 1363207361),
(7, 35, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:19.0) Gecko/20100101 Firefox/19.0', '172.24.1.143', 1363301612),
(8, 35, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:19.0) Gecko/20100101 Firefox/19.0', '172.24.1.143', 1363301751),
(9, 1, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:19.0) Gecko/20100101 Firefox/19.0', '172.24.1.143', 1363364574),
(10, 1, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17', '172.24.1.143', 1363374517),
(11, 1, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17', '172.24.1.143', 1363377701),
(12, 3, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17', '172.24.1.143', 1363714792),
(13, 3, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17', '172.24.1.143', 1363714911),
(14, 3, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17', '172.24.1.143', 1363714929),
(15, 3, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:19.0) Gecko/20100101 Firefox/19.0', '172.24.1.143', 1363715946),
(16, 3, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/536.28.10 (KHTML, like Gecko) Version/6.0.3 Safari/536.28.10', '172.24.1.161', 1363791080),
(17, 4, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/536.28.10 (KHTML, like Gecko) Version/6.0.3 Safari/536.28.10', '172.24.1.161', 1363791124),
(18, 1, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/536.28.10 (KHTML, like Gecko) Version/6.0.3 Safari/536.28.10', '172.24.1.161', 1363791144),
(19, 3, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_1) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.152 Safari/537.22', '172.24.1.143', 1363791365),
(20, 64, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_1) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.152 Safari/537.22', '172.24.1.143', 1363791650);

我按如下方式更改了查询,但仍然显示错误的结果......

你们可以看一下: -

SELECT l.uid,
    l.hostname,
    l.timestamp,
    c.country,
    l.times
FROM ip2nationCountries c
JOIN ip2nation i ON c.code = i.country
JOIN ( SELECT
        a.uid,
        a.hostname,
        MAX(a.timestamp) AS timestamp,
        COUNT(*) AS times
    FROM mslop_login_activity a
    WHERE a.uid = 3
    AND a.hostname = "157.191.122.36"
    GROUP BY a.hostname) AS l ON i.ip < INET_ATON( l.hostname )

2 个答案:

答案 0 :(得分:0)

您错过了加入。如果您使用正确的连接语法,这将更加明显,因此请将此作为课程,并在将来始终使用joinon子句。

您想要的查询:

    SELECT a.uid, a.hostname, a.timestamp, c.country, COUNT(*) AS times
    FROM login_activity a left outer join
         ip2nationCountries c
         on a.hostname = c.ip left outer join
         ip2nation i
         on i.ip < INET_ATON(a.hostname) AND c.code = i.country
    GROUP BY a.hostname
    ORDER BY times desc;

两条评论。我做了这些left outer join。如果主机名不匹配,则它们仍将显示在输出中(如果要过滤掉这些主机名,请更改为inner join)。其次,在加入其他表之前,您可能希望预先聚合login_activity表,如果它真的很大。

答案 1 :(得分:0)

这将为您提供用户ID,主机名以及他们在该主机上登录的次数。

SELECT a.uid, a.hostname, COUNT(*) AS times
FROM mslop_login_activity a
GROUP BY  a.uid, a.hostname
ORDER BY  times desc

要简化国家/地区,请使用视图计算范围。 (这种观点非常依赖于您获得有关IP地址如何映射到各国的准确完整数据。我没有尝试验证您的数据。)

create view ip_range as 
select t1.ip as ip_start
        , (select min(ip) - 1 from ip2nation where ip > t1.ip) ip_end
        , t1.country
from ip2nation t1

现在你应该可以使用简单明了的联接来获得这个国家。

SELECT a.uid
          , a.hostname
          , inet_aton(a.hostname) as ip_int
          , ip_range.country
FROM mslop_login_activity a
inner join ip_range
on inet_aton(a.hostname) between ip_range.ip_start and ip_range.ip_end

使用您的示例数据,这将不返回任何行。首先,登录活动的所有IP地址都在reserved range。另一方面,“ip2nation”中最长的IP地址(整数)是9位数;这还不够。我自己的IP地址转换为10位整数。

如果我将登录活动中的某个IP地址更新为转换为9位整数的美国IP地址,则上述查询会将该国家/地区正确识别为“US”。


这是您原始查询之一。它没有像你认为的那样做。

SELECT
     a.uid, a.hostname, a.timestamp, 
 COUNT(*) AS times
FROM
  login_activity a
GROUP BY
  a.hostname
ORDER BY
  times desc

返回此行。

uid  hostname      timestamp  times
--
3    172.24.1.143  1363038356 20

但是这个查询返回12行。请注意,12行不等于20次。

SELECT uid
FROM mslop_login_activity 
where uid = 3

在MySQL中使用GROUP BY是危险的,除非你知道自己在做什么,而且你真的非常小心。 (我不认为任何其他dbms将运行您的原始第一个查询,因为它不符合SQL。)