Поиск элемента в массиве составных типов - PullRequest
1 голос
/ 11 октября 2011

Использование PostgreSQL 9.0

У меня есть следующая таблица настроек

CREATE TABLE person (age integer, last_name text, first_name text, address text);

CREATE TABLE my_people (mperson person[]);

INSERT INTO my_people VALUES(array[ROW(44, 'John', 'Smith', '1234 Test Blvd.')::person]);

Теперь я хочу написать оператор выбора, который может искать и сравнивать значения моих составных типов в столбце массива mperson.

Пример:

SELECT * FROM my_people WHERE 20 > ANY( (mperson) .age);

Однако при попытке выполнить этот запрос я получаю следующую ошибку:

ERROR:  column notation .age applied to type person[], which is not a composite type
LINE 1: SELECT mperson FROM my_people WHERE 20 > ANY((mperson).age);

Итак, вы можете видеть, что я пытаюсь проверить значения составного типа внутри моего массива.

Я знаю, я не должен использовать массивы и композиты в своих таблицах, но это лучше всего соответствует требованиям наших приложений.

Кроме того, у нас есть несколько вложенных составных массивов, поэтому будет полезно общее решение, которое позволило бы мне искать на многих уровнях.

Ответы [ 2 ]

3 голосов
/ 11 октября 2011

Временная настройка теста:

CREATE TEMP TABLE person (age integer, last_name text, first_name text
                                                     , address text);
CREATE TEMP TABLE my_people (mperson person[]);

-- test-data, demonstrating 3 different syntax styles:
INSERT INTO my_better_people (mperson)
VALUES
   (array[(43, 'Stack', 'Over', '1234 Test Blvd.')::person])

  ,(array['(44,John,Smith,1234 Test Blvd.)'::person,
          '(21,Maria,Smith,1234 Test Blvd.)'::person])

  ,('{"(33,John,Miller,12 Test Blvd.)",
      "(22,Frank,Miller,12 Test Blvd.)",
      "(11,Bodi,Miller,12 Test Blvd.)"}');

Звоните ( почти решение ):

SELECT (p).*
FROM   (
   SELECT unnest(mperson) AS p
   FROM   my_people) x
WHERE  (p).age > 33;

Возвращает:

 age | last_name | first_name |     address
-----+-----------+------------+-----------------
  43 | Stack     | Over       | 1234 Test Blvd.
  44 | John      | Smith      | 1234 Test Blvd.
  • - это функция unnest (), которая доступна в 9.0 .
  • Ваша ошибка в этом примере заключается в том, что вы забыли о промежуточном слое ARRAY. unnest() возвращает одну строку для каждого базового элемента, затем вы можете получить доступ к столбцам в сложном типе, как показано.

Храбрый новый мир

ЕСЛИ вам действительно нужен целый человек, а не человек, отвечающий критериям, я предлагаю вам добавить первичный ключ в таблицу и действовать следующим образом:

CREATE TEMP TABLE my_better_people (id serial, mperson person[]);

-- shortcut to populate the new world by emigration from the old world ;)
INSERT INTO my_better_people (mperson)
SELECT mperson FROM my_people;

Поиск людей:

SELECT id, (p).*
FROM  (
   SELECT id, unnest(mperson) AS p
   FROM   my_better_people) x
WHERE  (p).age > 20;

Найти целых людей ( решение ):

SELECT *
FROM   my_better_people p
WHERE  EXISTS (
   SELECT 1 
   FROM (
      SELECT id, unnest(mperson) AS p
      FROM   my_better_people
      ) x
   WHERE  (p).age > 20
   AND    x.id = p.id
   );
  • Вы можете сделать это без первичного ключа, но это было бы глупо.
3 голосов
/ 11 октября 2011

Конструкция ЛЮБОЙ в вашем случае выглядит избыточной. Вы можете написать запрос так:

SELECT * FROM my_people WHERE (mperson[1]).age < 20;

Конечно, если у вас есть несколько значений в этом массиве, это не сработает, но вы не можете получить точный элемент массива иначе.

Зачем вам вообще нужны массивы? Вы можете просто написать один элемент типа person на строку.

Проверьте также отличный модуль HStore , который может лучше соответствовать вашим общим потребностям.

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