[英]Postgresql join only most specific cidr match
I have a table "test_networks" that is a list of networks with a description about what each network is and where it is located. 我有一个表“test_networks”,它是一个网络列表,其中描述了每个网络的位置和位置。
CREATE TABLE test_networks
(
id serial PRIMARY KEY,
address cidr,
description text
);
The field "address" will be any of the following: 字段“地址”将是以下任意一项:
I also have a table "test_systems" which contains a list of systems and their properties (I have a few more properties, but those are irrelevant): 我还有一个表“ test_systems”,其中包含系统及其属性的列表(我还有其他一些属性,但是无关紧要):
CREATE TABLE test_systems
(
id serial PRIMARY KEY,
address inet,
owner text
);
Lets assume I have systems with the following addresses: 假设我的系统具有以下地址:
I want to create a report of all systems and their closest networks description (or empty description if no network is found). 我想创建所有系统及其最近网络描述的报告(如果找不到网络,则为空描述)。 As you can see, 10.1.1.1 matches multiple networks, so I only want to list the most specific one (ie the one with the highest masklen()) for each system.
如您所见,10.1.1.1匹配多个网络,因此我只想列出每个系统中最具体的一个(即masklen()最高的那个)。 Example output would be:
示例输出将是:
hostaddr | netaddr | description
----------+-------------+----------------
10.1.1.1 | 10.1.1.0/24 | third network
10.2.0.1 | 10.2.0.0/16 | 4th network
I tried using this query: 我尝试使用此查询:
SELECT s.address AS hostaddr, n.address AS netaddr, n.description AS description
FROM test_systems s
LEFT JOIN test_networks n
ON s.address << n.address;
However, this will give me a list of all system + network pairs, eg: 但是,这将为我提供所有系统+网络对的列表,例如:
hostaddr | netaddr | description
----------+-------------+----------------
10.1.1.1 | 10.0.0.0/8 | first network
10.1.1.1 | 10.1.0.0/16 | second network
10.1.1.1 | 10.1.1.0/24 | third network
10.2.0.1 | 10.0.0.0/8 | first network
10.2.0.1 | 10.2.0.0/16 | 4th network
Does anyone know how I can query for only the most specific network for each system? 有谁知道我如何只查询每个系统的最具体的网络?
You're looking for the "top n in group" query, where n = 1 in this case. 您正在查找“组中前n个”查询,在这种情况下,其中n = 1。 You can do this using the
row_number()
window function: 您可以使用
row_number()
窗口函数执行此操作:
SELECT x.hostaddr, x.netaddr, x.description FROM (
SELECT
s.address AS hostaddr,
n.address AS netaddr,
n.description AS description,
row_number() OVER (
PARTITION BY s.address
ORDER BY masklen(n.address) DESC
) AS row
FROM test_systems s
LEFT JOIN test_networks n
ON s.address << n.address
) x
WHERE x.row = 1;
SELECT distinct on (s.address)
s.address AS hostaddr,
n.address AS netaddr,
n.description AS description
FROM
test_systems s
LEFT JOIN
test_networks n ON s.address << n.address
order by s.address, masklen(n.address) desc
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.