Postgres | Как получить строки в соответствии с точным или меньшим списком IP-адресов и простым текстовым списком - PullRequest
0 голосов
/ 05 августа 2020

У меня есть таблица, содержащая 2 текстовых столбца: тип и IP. Оба они могут представлять собой один текст или несколько текстов, разделенных символом '@ ## @'. кроме того, ip также может быть диапазоном, например 1.1.1.1/24

таблица ниже

row |type       | ip
-------------------------------------------
1   |red           | 1.1.1.1
2.  |red@##@blue   | 1.1.1.1@##@2.2.2.2
3.  |blue          | 1.1.1.1/32@##@2.2.2.2/32
4.  |yellow        | 1.1.1.1
5.  |red           | 3.3.3.3
6.  |yellow@##@red | 1.1.1.1
7.  |blue          | 1.1.1.1@##@3.3.3.3

Я хочу получить все строки, которые имеют тип красный или синий или оба (точно красный и синий или меньше, что означает один красный или один синий) И IP 1.1.1.1 или 2.2.2.2 или оба, включая диапазоны (точно 1.1.1.1 и 2.2.2.2 или меньше, что означает один 1.1.1.1 или один 2.2.2.2 или если у нас несколько IP-адресов, они должны точно или меньше соответствовать диапазону)

означает, что я хочу получить строки 1,2,3

Я начал писать следующий запрос но не могу понять:

    SELECT * FROM t where
    regexp_split_to_array(t.type, '@##@')::text[] in ('red','blue')
    and
    regexp_split_to_array(t.ip, '@##@')::inet[] in ('1.1.1.1','2.2.2.2')

Заранее спасибо!

Ответы [ 2 ]

0 голосов
/ 05 августа 2020

Сопоставление type, так что одно, другое или оба совпадения могут быть выполнены с помощью оператора включения, поскольку базовое сравнение является равенством.

Сопоставление типов inet с подсетями - это совсем другая история. Это должно использовать оператор inet && (содержит или содержится в), поэтому массив ip должен быть преобразован в строки с помощью unnest. Требование повторного сопоставления одного, другого или обоих означает, что нам нужно количество ip значений и возвращать строки только тогда, когда количество совпадений равно количеству ip значений.

Этот запрос, похоже, сделать работу. Скрипка здесь.

with asarrays as (
  SELECT row, regexp_split_to_array(t.type, '@##@')::text[] as types,
         unnest(regexp_split_to_array(t.ip, '@##@')::inet[]) as ip
    FROM t
), typematch as (
  select *, count(*) over (partition by row) as totcount
    from asarrays 
   where types <@ array['red', 'blue']
), ipmatch as (  
  select *, count(*) over (partition by row) as matchcount
    from typematch
   where ip && any(array['1.1.1.1'::inet, '2.2.2.2'::inet])
)
select row, types, array_agg(ip) as ip 
  from ipmatch
 where matchcount = totcount
 group by row, types;
0 голосов
/ 05 августа 2020

Вам нужен оператор перекрытия:

SELECT *
FROM t
WHERE regexp_split_to_array(t.type, '@##@')::text[] && array['red', 'blue'] and
      regexp_split_to_array(t.ip, '@##@')::inet[] && array['1.1.1.1', '2.2.2.2']
...