Получение определенных элементов массива в одной строке (PostgreSQL) - PullRequest
0 голосов
/ 17 февраля 2012

Вот моя проблема:

У меня есть таблица с 4 столбцами (тип = массив, одномерное) со значениями вроде:

   ID        c1             c2           c3

   1      {1, 2, 3}    {10, 20, 30}   {100, 200, 300}
   2      {4, 5, 6}    {11, 22, 33}   {111, 222, 333}

Мне было интересно, возможно липолучить результат, подобный следующему:

   select ID, c1, c2, c3 from t1 where c3 = 200 (<---- pseudo-statement!)

Результат:

   1, 2, 20, 200

или

   select ID, c1, c2, c3 from t1 where c3 = 333 

Результат:

    1, 6, 33, 333

Так чтоЯ хочу, чтобы получить соответствующие значения значения в инструкции where.

Есть ли способ получить решение для этого?

Ответы [ 2 ]

2 голосов
/ 17 февраля 2012

(Edit1: упрощенный, Edit2: более широкий охват)

Решения для любой длина массива.Также возвращает все попадания, даже в нескольких позициях в одном или нескольких массивах одновременно.

Если вам известна фиксированная длина одномерного массива, вы можете жестко закодировать егов generate_series(), для самого простого и быстрого решения :

SELECT id, c1[i], c2[i], c3[i]
FROM   tbl, generate_series(1, 3) i
WHERE  c3[i] = 200;

Если все массивы в c3 имеют одно и то же неизвестноедлина , вы можете обобщить с очень небольшими затратами:

SELECT id, c1[i], c2[i], c3[i]
FROM   tbl, generate_subscripts((SELECT c3 FROM tbl LIMIT 1), 1) s(i)
WHERE  c3[i] = 200;

Обратите внимание, что я использую удобную функцию generate_subscripts() здесь.
Для больших индексов, чем верхняяпредел, элементы массива просто NULL и выпадают из запроса.


Если неизвестная длина массива в c3 на самом деле изменяется Вы можете обобщить еще немного, с более высокой стоимостью:

SELECT id, c1[i], c2[i], c3[i]
FROM   tbl
FROM   tbl, generate_series(1, (SELECT max(array_upper(c3, 1)) FROM tbl)) s(i)
WHERE  c3[i] = 200;

Наконец, для нестандартных индексов массива кроме того, то же самое можно сделать так:

SELECT id, c1[i], c2[i], c3[i]
FROM   tbl
     , generate_subscripts((SELECT c3 FROM tbl
                            ORDER  BY array_length(c3,1) DESC LIMIT 1), 1) s(i)
WHERE  c3[i] = 200;

Мгновенный испытательный стенд:

WITH tbl (id, c1, c2, c3) AS (
    VALUES
     (1, '{1, 2, 3}'::int[], '{10, 20, 30}'::int[], '{100, 200, 300}'::int[])
    ,(2, '{4, 5, 6}', '{11, 22, 33}', '{111, 222, 333}')
-- un-comment to test 333 in all positions of c3 and varying array length
--  ,(3, '{7, 8, 9, 10}', '{14, 25}', '{333, 333, 333, 333}')
    )
SELECT id, c1[i], c2[i], c3[i]
FROM tbl
    ,generate_subscripts((SELECT c3 FROM tbl
                          ORDER  BY array_length(c3,1) DESC LIMIT 1), 1) s(i)
WHERE  c3[i] = 333;
1 голос
/ 17 февраля 2012

Вам необходимо использовать generate_series для создания перекрестного соединения вашей таблицы и всех индексов ваших массивов (здесь это будет 1,2,3):

select *
from (
  select yourtab.id
  ,      yourtab.c1[tidx.idx]
  ,      yourtab.c2[tidx.idx]
  ,      yourtab.c3[tidx.idx]
  from yourtab
  cross join generate_series(1, 3) tidx(idx)
) t(id, c1, c2, c3)
where c3 = 333

Обратите внимание на предположение, что каждый массив всегда будет иметь 3 элемента.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...