Postgres: перевірити, чи містить поле масиву значення?


82

Я впевнений, що це дублікат запитання в тому сенсі, що відповідь там десь є, але я не міг знайти відповідь після Гугління впродовж 10 хвилин, тому звертаюся до редакції з проханням не закривати його на підставі того, що це цілком може бути корисно для інших людей.

Я використовую Postgres 9.5. Це моя таблиця:

        Column          │           Type            │                                Modifiers
─────────────────────────┼───────────────────────────┼─────────────────────────────────────────────────────────────────────────
 id                      │ integer                   │ not null default nextval('mytable_id_seq'::regclass)
 pmid                    │ character varying(200)    │
 pub_types               │ character varying(2000)[] │ not null

Я хочу знайти всі рядки з "Журналом" у pub_types.

Я знайшов документи і погуглив, і ось що я спробував:

select * from mytable where ("Journal") IN pub_types;
select * from mytable where "Journal" IN pub_types;
select * from mytable where pub_types=ANY("Journal");
select * from mytable where pub_types IN ("Journal");
select * from mytable where where pub_types contains "Journal";

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

Відповіді:


151

Це має спрацювати:

select * from mytable where 'Journal'=ANY(pub_types);

тобто синтаксис є <value> = ANY ( <array> ). Також зверніть увагу, що рядкові літерали в postresql пишуться з одинарними лапками.


@redneb як щодо того, чи хочу я перевірити, чи містить поле масив елемент у масиві?
Аарон

Я отримуюERROR: input of anonymous composite types is not implemented
Шейн

Це те саме, що <value> IN ( <array> )?
jallen0927

INочікує явного списку значень (або підзапиту), тоді як ANYпрацює з масивами. Це може бути корисно, якщо у вас є список значень, що вже є в масиві, наприклад, коли масив зберігається в якомусь стовпці в db, як у випадку з OP.
redneb

2
а як щодо цього синтаксису щодо продуктивності? виберіть * з таблиці my, де pub_types @> array ['Journal' :: text];
Ніна

46

За допомогою БУДЬ-ЯКОГО оператора ви можете шукати лише одне значення.

Наприклад,

select * from mytable where 'Book' = ANY(pub_types);

Якщо ви хочете знайти кілька значень, ви можете використовувати оператор @> .

Наприклад,

select * from mytable where pub_types @> '{"Journal", "Book"}';

Ви можете вказати, в якому порядку вам подобається.


24
@>означає, що містить усі значення в цьому масиві. Якщо ви хочете здійснити пошук, чи містить поточний масив будь-які значення в іншому масиві, ви можете використовувати &&. select * from mytable where pub_types && '{"Journal", "Book"}';
jallen0927

1
Я не знаю, чи це версія версії, але як @>, так і&& працювали абсолютно однаково для мене на Postgres 9.6. Вони обидва відповідали будь-якому пункту у списку. За винятком того, що @> також відповідає порожньому списку "{}".
Марцелус Троян

8

Це спрацювало для мене:

select * from mytable
where array_to_string(pub_types, ',') like '%Journal%'

Залежно від ваших потреб у нормалізації, можливо, було б краще застосувати окрему таблицю з посиланням на FK, оскільки ви можете отримати кращу продуктивність та керованість.


Як і теги, якщо ви не плануєте вести таблицю тегів або маєте лише одну сутність, яка їх використовує.
barnacle.m

1
Це дасть помилкові спрацьовування, якщо у вас є кілька значень з однаковим префіксом, тобто "Записи журналу"
полудень

1
Те, як ОП формулював запитання, здається, він хотів знайти Журнал, який з'являється де завгодно в рядку. Якщо ви хочете відповідати лише там, де саме це слово "Журнал", просто видаліть провідні та кінцеві символи підстановки (тобто%).
Шейн

1
Хороший - дозволив мені робити запит ILIKE над масивом; Дякую! SELECT * FROM archive WHERE ARRAY_TO_STRING(kw, ',') ILIKE '%pLASt%';
Victoria Stuart

2

Замість INми можемо використовувати ANYз масивами, відлитими до перерахування масиву, наприклад:

create type example_enum as enum (
  'ENUM1', 'ENUM2'
);

create table example_table (
  id integer,
  enum_field example_enum
);

select 
  * 
from 
  example_table t
where
  t.enum_field = any(array['ENUM1', 'ENUM2']::example_enum[]);

Або ми все ще можемо використовувати речення "IN", але спочатку нам слід "зняти" це:

select 
  * 
from 
  example_table t
where
  t.enum_field in (select unnest(array['ENUM1', 'ENUM2']::example_enum[]));

Приклад: https://www.db-fiddle.com/f/LaUNi42HVuL2WufxQyEiC/0


-1

Це спрацювало для мене

let exampleArray = [1, 2, 3, 4, 5];
let exampleToString = exampleArray.toString(); //convert to toString
let query = `Select * from table_name where column_name in (${exampleToString})`; //Execute the query to get response

У мене така сама проблема, а через годину зусиль я дізнався, що масив не повинен отримувати безпосередній доступ до запиту. Тоді я виявив, що дані слід надсилати у самому парантэзі, потім знову перетворив цей масив на рядок, використовуючи метод toString у js. Отже, я працював, виконуючи наведений вище запит, і отримав очікуваний результат


4
Будь ласка, завжди додайте пояснення до коду. Це покращить якість вашої відповіді.
DaFois
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.