Magicked
Magicked

Reputation: 647

Mysql: Select specific data from multiple joined tables

I'm having trouble wrapping my brain around this select statement. The data is coming from 3 tables (I've cut out all unnecessary data for easier readability):

mysql> describe vulnerability;
+---------------+------------------+------+-----+---------+----------------+
| Field         | Type             | Null | Key | Default | Extra          |
+---------------+------------------+------+-----+---------+----------------+
| vuln_id       | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| severity      | int(10) unsigned | NO   |     | NULL    |                |
| host_id       | int(10) unsigned | NO   | MUL | NULL    |                |
+---------------+------------------+------+-----+---------+----------------+

mysql> describe cve;
+---------+------------------+------+-----+---------+----------------+
| Field   | Type             | Null | Key | Default | Extra          |
+---------+------------------+------+-----+---------+----------------+
| cve_id  | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| cve     | varchar(15)      | NO   |     | NULL    |                |
| vuln_id | int(10) unsigned | NO   | MUL | NULL    |                |
| year    | int(4) unsigned  | YES  |     | NULL    |                |
+---------+------------------+------+-----+---------+----------------+

mysql> describe host;
+--------------+------------------+------+-----+---------+----------------+
| Field        | Type             | Null | Key | Default | Extra          |
+--------------+------------------+------+-----+---------+----------------+
| host_id      | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| ip_addr      | int(10) unsigned | NO   |     | NULL    |                |
+--------------+------------------+------+-----+---------+----------------+

I want to output the number of hosts that have vulnerabilities that are less than the year 2009 with severity = 3. The year is contained in CVE, which is tied to Vulnerability with the vuln_id FK. The vulnerability has the severity and is tied to Host with the host_id FK. Here is what I have so far:

mysql> select count(distinct ip_addr) from host H 
  inner join vulnerability V on H.host_id = V.host_id 
  inner join CVE C on C.vuln_id = V.vuln_id 
  where V.severity = 3 and C.year < 2009;
+-------------------------+
| count(distinct ip_addr) |
+-------------------------+
|                    5071 |
+-------------------------+

This tells me the total number of hosts with vulnerabilities older than 2009, which is a good start. However, I want to take it a step further and only include those hosts that have 50 or more vulnerabilities. I'm not sure how to do this. Each host entry in the Host table has multiple corresponding Vulnerability entries. I assume I need to add something in my where clause, but I'm stuck.

Thanks in advance. Please let me know if more information is needed.

Upvotes: 1

Views: 649

Answers (1)

Mark Byers
Mark Byers

Reputation: 837946

Try using GROUP BY and HAVING:

SELECT ip_addr
FROM host AS H
INNER JOIN vulnerability AS V
    ON H.host_id = V.host_id
INNER JOIN CVE AS C
    ON C.vuln_id = V.vuln_id
WHERE V.severity = 3 AND C.year < 2009
GROUP BY ip_addr
HAVING COUNT(DISTINCT vuln_id) >= 50

To just get the count wrap the above query inside another query:

SELECT COUNT(*) FROM
(
     SELECT ip_addr
     FROM host AS H
     -- etc... same query as above
) T1

Upvotes: 2

Related Questions