MySQL将child + parent连接到同一个表中,然后将其与另一个表

时间:2016-09-08 13:45:03

标签: mysql join

我有两个表,第一个有ipaddresses和ipsubnets。该表包含ip,netmask和所有权等信息。每个ip在同一个表中都有一个父级。父节点是具有网络掩码的网络地址。此表中99,99%的行具有父级。

另一个表具有连接到IP地址的所有权名称。

在我的表中,大多数单个ipaddressess(带有netmask / 32)没有所有权。当表是子网(小于/ 32前缀)时,该表几乎仅填充所有权。

问题是,当我在行上找不到所有权时,我想使用父母所有权。我还没有能够实现这一点,我不确定我是否使用了正确的技术。

这是来自ipblock的create语句。

CREATE TABLE `ipblock` (
`address` DECIMAL(40,0) NOT NULL,
`description` VARCHAR(128) NULL DEFAULT NULL,
`first_seen` TIMESTAMP NOT NULL DEFAULT '1970-01-02 01:00:01',
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`info` TEXT NULL,
`interface` BIGINT(20) NULL DEFAULT NULL,
`last_seen` TIMESTAMP NOT NULL DEFAULT '1970-01-02 01:00:01',
`owner` BIGINT(20) NULL DEFAULT NULL,
`parent` BIGINT(20) NULL DEFAULT NULL,
`prefix` INT(11) NOT NULL,
`status` BIGINT(20) NOT NULL,
`used_by` BIGINT(20) NULL DEFAULT NULL,
`version` INT(11) NOT NULL,
`vlan` BIGINT(20) NULL DEFAULT NULL,
`use_network_broadcast` TINYINT(1) NOT NULL,
`monitored` TINYINT(1) NOT NULL,
`rir` VARCHAR(255) NULL DEFAULT NULL,
`asn` BIGINT(20) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `ipblock1` (`address`, `prefix`),
INDEX `Ipblock2` (`parent`),
INDEX `Ipblock3` (`status`),
INDEX `Ipblock4` (`first_seen`),
INDEX `Ipblock5` (`last_seen`),
INDEX `Ipblock6` (`interface`),
INDEX `Ipblock7` (`vlan`),
INDEX `Ipblock8` (`version`),
INDEX `owner` (`owner`),
INDEX `used_by` (`used_by`),
INDEX `asn` (`asn`),
CONSTRAINT `fk_asn` FOREIGN KEY (`asn`) REFERENCES `asn` (`id`),
CONSTRAINT `fk_interface_3` FOREIGN KEY (`interface`) REFERENCES `interface` (`id`),
CONSTRAINT `fk_owner_2` FOREIGN KEY (`owner`) REFERENCES `entity` (`id`),
CONSTRAINT `fk_parent` FOREIGN KEY (`parent`) REFERENCES `ipblock` (`id`),
CONSTRAINT `fk_status_2` FOREIGN KEY (`status`) REFERENCES `ipblockstatus` (`id`),
CONSTRAINT `fk_used_by_1` FOREIGN KEY (`used_by`) REFERENCES `entity` (`id`),
CONSTRAINT `fk_vlan_1` FOREIGN KEY (`vlan`) REFERENCES `vlan` (`id`))
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=29404762
;

这是来自实体表。

CREATE TABLE `entity` (
`acctnumber` VARCHAR(128) NULL DEFAULT NULL,
`aliases` VARCHAR(255) NULL DEFAULT NULL,
`asname` VARCHAR(32) NULL DEFAULT NULL,
`asnumber` INT(11) NULL DEFAULT NULL,
`availability` BIGINT(20) NULL DEFAULT NULL,
`config_type` VARCHAR(255) NULL DEFAULT NULL,
`contactlist` BIGINT(20) NULL DEFAULT NULL,
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`info` TEXT NULL,
`maint_contract` VARCHAR(128) NULL DEFAULT NULL,
`name` VARCHAR(128) NOT NULL,
`oid` VARCHAR(32) NULL DEFAULT NULL,
`short_name` VARCHAR(64) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `entity1` (`name`),
UNIQUE INDEX `entity2` (`oid`),
INDEX `Entity3` (`asname`),
INDEX `Entity4` (`asnumber`),
INDEX `availability` (`availability`),
INDEX `contactlist` (`contactlist`),
CONSTRAINT `fk_availability` FOREIGN KEY (`availability`) REFERENCES `availability` (`id`),
CONSTRAINT `fk_contactlist_2` FOREIGN KEY (`contactlist`) REFERENCES `contactlist` (`id`))
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=146
;

这是我一直在玩的问题:

SELECT 
INET_NTOA(ipblock.address) AS "Address",
ipblock.prefix AS "Netmask",
IF (ipblock.used_by IS NULL,
    parentNAME.name,
    entity.name) AS "Used by"

FROM ipblock

LEFT JOIN ipblock AS parentIP
ON ipblock.parent = parentIP.id

LEFT JOIN entity
ON ipblock.used_by = entity.id
#AND parentIP.used_by = entity.id

LEFT JOIN entity AS parentNAME
ON parentIP.used_by = entity.id

group by ipblock.id, parentIP.id
#order by parentIP.id

第一个LEFT JOIN我希望创建一个名为parentIP的ipblock表的别名。自从每个ipblock。 row有父,我想ipblock.parent是parentIP.id。这似乎按预期工作。

第二个LEFT JOIN是使used_by字段连接到entity.id。这也可以按预期工作,我可以从拥有所有权的人那里选择entity.name。

第三个LEFT JOIN我尝试再次将先前创建的别名parentIP.used_by连接到entity.id。当我在select中输出我的IF语句输出parentNAME.name时,我没有得到预期的结果。只有entity.name有效。

我在这里使用了错误的技巧吗?

| Address | Netmask | Used by |
| 172.18.5.0 | 24 | Network Services | 
| 172.18.5.7 | 32 | NULL | 
| 172.18.5.24 | 32 | NULL | 
| 172.16.40.0 | 24 | company-xyz | 
| 172.16.41.0 | 24 | company-xyz | 
| 172.18.30.0 | 24 | Network Services | 
| 172.18.30.2 | 32 | NULL | 
| 172.18.30.3 | 32 | NULL | 
| 172.24.0.40 | 29 | company-xyz | 
| 172.18.5.25 | 32 | Network Services | 
| 172.16.80.0 | 24 | 1234-customer | 
| 172.16.80.2 | 32 | 1234-customer | 
| 172.24.0.24 | 29 | 1234-customer | 
| 10.0.1.0 | 24 | NULL | 
| 172.24.0.0 | 29 | internal-service2 | 
| 172.18.5.15 | 32 | Network Services | 
| 172.18.222.224 | 29 | NULL | 
| 172.18.222.248 | 32 | NULL | 
| 172.18.222.188 | 32 | NULL | 

数据库中的更多示例列以获得更好的概述。

```sql
SELECT 
    INET_NTOA(ipblock.address),
    ipblock.prefix,
    ipblock.id,
    ipblock.parent AS "parent id",
    ipblock.used_by AS "entity id",
    entity.name,
    ipblock.id
FROM ipblock
    LEFT JOIN entity
    ON ipblock.used_by = entity.id

```
| INET_NTOA(ipblock.address) | prefix | id | parent id | entity id | name | id | 
| - | -: | -: | -: | -: | - | -: | 
| NULL | 10 | 6 | NULL | 1 | Unknown | 6 | 
| 172.18.5.0 | 24 | 15 | 29343867 | 24 | Network Services | 15 | 
| 172.18.5.7 | 32 | 20 | 15 | NULL | NULL | 20 | 
| 172.18.5.24 | 32 | 38 | 15 | NULL | NULL | 38 | 
| 172.16.40.0 | 24 | 40 | 25389918 | 68 | customer-abc | 40 | 
| 172.16.41.0 | 24 | 46 | 25389918 | 68 | customer-abc | 46 | 
| 172.18.30.0 | 24 | 52 | 29343867 | 24 | Network Services | 52 | 
| 172.18.30.2 | 32 | 54 | 52 | NULL | NULL | 54 | 
| 172.18.30.3 | 32 | 55 | 52 | NULL | NULL | 55 | 
| 172.24.0.40 | 29 | 58 | 27082404 | 68 | customer-abc | 58 | 
| 172.18.5.25 | 32 | 64 | 15 | 24 | Network Services | 64 | 
| 172.16.80.0 | 24 | 66 | 25389918 | 131 | cust | 66 | 
| 172.16.80.2 | 32 | 68 | 66 | 131 | cust | 68 | 
| 172.24.0.24 | 29 | 72 | 27082404 | 131 | cust | 72 | 
| 10.0.1.0 | 24 | 79 | 3 | NULL | NULL | 79 | 
| 172.24.0.0 | 29 | 85 | 27082404 | 73 | xyz-customer | 85 | 
| 172.18.5.15 | 32 | 91 | 15 | 24 | Network Services | 91 | 

我是SQL的新手,所以请向我解释,就像我是5.

1 个答案:

答案 0 :(得分:0)

我相信你第三次加入错了。查询中的第三个连接如下:

LEFT JOIN entity AS parentNAME
ON parentIP.used_by = entity.id

您未加入parentName子句中的on别名,而是加入基本entity别名。它应该是

LEFT JOIN entity AS parentNAME
ON parentIP.used_by = parentNAME.id

在这种情况下,我认为您不需要group by子句。我还会改变你计算used by表达式的方式:

coalesce(entity.name, parentNAME.name) AS "Used by"

Coalesce()函数返回其参数列表中的第一个非空值,如果没有提供非空值作为参数,则返回null。