Sprawdź, czy istnieje wartość w tablicy Postgres

196

Korzystając z Postgres 9.0, potrzebuję sposobu na sprawdzenie, czy wartość istnieje w danej tablicy. Do tej pory wymyśliłem coś takiego:

select '{1,2,3}'::int[] @> (ARRAY[]::int[] || value_variable::int)

Ale ciągle myślę, że powinien istnieć prostszy sposób, po prostu tego nie widzę. To wydaje się lepsze:

select '{1,2,3}'::int[] @> ARRAY[value_variable::int]

Wierzę, że to wystarczy. Ale jeśli masz na to inne sposoby, udostępnij je!

Mike Starov
źródło

Odpowiedzi:

323

Prostsze w ANYkonstrukcji:

SELECT value_variable = ANY ('{1,2,3}'::int[])

Właściwym operandem ANY(między nawiasami) może być albo zestaw (na przykład wynik zapytania podrzędnego) albo tablica . Istnieje kilka sposobów korzystania z niego:

Ważna różnica: (operatorzy tablicowe <@, @>, &&et al.) Oczekiwać tablicy typów jako argumenty i wsparcia GIN lub indeksów z GIST w standardowym rozkładzie PostgreSQL, natomiast ANYkonstrukcja oczekuje elementem typu, lewy argument i nie posiada tych wskaźników. Przykład:

Nic z tego nie działa w przypadku NULLelementów. Aby przetestować NULL:

Erwin Brandstetter
źródło
Dzięki. Musiał pominąć tę część instrukcji. To działa świetnie. Ma efekt uboczny automatycznego odlewania. Np .: WYBIERZ 1 :: smallint = ANY ('{1,2,3}' :: int []) działa. Upewnij się, że umieścisz DOWOLNĄ () po prawej stronie wyrażenia.
Mike Starov
Dziękuję za odpowiedź. Mam problem z tym, że moje zapytanie działało lokalnie, ale w heroku rzucałem tę wiadomość ANY/ALL (array) requires array on right side, dodałem ::int[]uroku.
kinduff 13.12.12
gdzie S.employee_id <@ DOWOLNY ('”+ pracownikIDsArray +"' :: int []) Zwraca wyjątek PSQLE: BŁĄD: brak wartości wymiaru
Ramprasad
3
Chociaż jest to pytanie dotyczące dinozaurów w latach internetowych, powolni ludzie tacy jak ja powinni być świadomi, że 'something' = ANY(some_array)można je również wykorzystać w WHEREklauzuli. Z powodów znanych tylko Cromowi przez ostatnie cztery lata myślałem, że nie mogę używać komparatorów tablicowych w WHEREklauzulach. Te dni już minęły. (Zostałem upuszczony na głowę jako dziecko, więc może to tylko ja).
GT.
1
@GT .: Istota: każde boolean wyrażenie działa w WHEREklauzuli - Crom chętnie.
Erwin Brandstetter,
90

Uważaj na pułapkę, w którą wpadłem: sprawdzając, czy pewna wartość nie jest obecna w tablicy, nie powinieneś:

SELECT value_variable != ANY('{1,2,3}'::int[])

ale użyj

SELECT value_variable != ALL('{1,2,3}'::int[])

zamiast.

morderstwo
źródło
2
Rodzaj podwójnego negatywu; zauważ jego użycie ALLvsANY
vol7ron
43
SELECT NOT value_variable = ANY('{1,2,3}'::int[])może być bardziej czytelny
Ondřej Bouda
28

ale jeśli masz na to inne sposoby, udostępnij.

Możesz porównać dwie tablice. Jeśli którakolwiek z wartości w lewej tablicy nakłada się na wartości w prawej tablicy, wówczas zwraca wartość true. To trochę hackish, ale działa.

SELECT '{1}'   && '{1,2,3}'::int[];  -- true
SELECT '{1,4}' && '{1,2,3}'::int[];  -- true
SELECT '{4}'   && '{1,2,3}'::int[];  -- false
  • W pierwszym i drugim zapytaniu wartość 1znajduje się we właściwej tablicy
  • Zauważ, że drugie zapytanie jest true, mimo że wartość 4nie jest zawarta we właściwej tablicy
  • W przypadku trzeciego zapytania żadne wartości w lewej tablicy (tj. 4) Nie znajdują się w prawej tablicy, więc zwracafalse
vol7ron
źródło
jak mogę wyszukać kolumnę z innej tabeli, aby mieć wartość w tablicy? np. wybierz * z piw, w których style_id jest (wybierz preferencje od użytkowników, gdzie id = 1) limit 1; style_id jest liczbą całkowitą typu danych; preferencje są liczbami całkowitymi [] Otrzymuję ten błąd BŁĄD: operator nie istnieje: liczba całkowita = liczba całkowita [] LINIA 1: wybierz * z piw, w których style_id jest (wybierz preferencje f ... ^ WSKAZÓWKA: Żaden operator nie pasuje do podanej nazwy i typu argumentu (s) Może być konieczne dodanie rzutowania typu jawnego
HP
@HP Istnieją różne sposoby rozwiązania tego pytania, powinieneś zadać nowe pytanie
vol7ron
czy jesteś pewien, że nie ma już pytania? @ vol7ron
HP
@HP Wcale nie, ale komentarze dotyczą komentarzy dotyczących pytania lub odpowiedzi; zazwyczaj w celu dodania większej ilości informacji lub uzyskania większej ilości informacji, które nie zostały rozwiązane. Zadajesz pytanie niezwiązane z tą odpowiedzią. Myślę, że będziesz miał więcej szczęścia, zadając pytanie jako nowy post, a nie w komentarzu;)
vol7ron
@ HP, jeśli nie opublikowałeś swojego pytania, możesz zobaczyć tutaj: sqlfiddle.com/#!15/144cd/3, aby zobaczyć przykład tego, co musisz zrobić - Twój problem jest inny, ponieważ musisz rozproszyć tablicę.
vol7ron
4

unnestmożna również użyć. Rozszerza tablicę do zestawu wierszy, a następnie sprawdzenie, czy wartość istnieje lub nie jest tak proste, jak użycie INlub NOT IN.

na przykład

  1. id => uuid

  2. wyjątek_list_ids => uuid []

select * from table where id NOT IN (select unnest(exception_list_ids) from table2)

pg2286
źródło
Tak. Zauważ, że w moich planach zapytań SELECT UNNEST nie jest tak dobry, jak = ANY. Polecam sprawdzenie planów zapytań, aby sprawdzić, czy masz to, czego chcesz / oczekujesz.
Rob Bygrave
3

Podczas szukania istnienia elementu w tablicy wymagane jest odpowiednie rzutowanie, aby przekazać parser SQL postgres. Oto jedno przykładowe zapytanie wykorzystujące tablicę zawierającą operator w klauzuli złączenia:

Dla uproszczenia wymieniam tylko odpowiednią część:

table1 other_name text[]; -- is an array of text

Pokazano dołączoną część SQL

from table1 t1 join table2 t2 on t1.other_name::text[] @> ARRAY[t2.panel::text]

Działa również następujące

on t2.panel = ANY(t1.other_name)

Zgaduję tylko, że wymagane jest dodatkowe rzutowanie, ponieważ analiza nie musi pobierać definicji tabeli, aby ustalić dokładny typ kolumny. Inni komentują to.

Kemin Zhou
źródło
1

Cześć, ten działa dla mnie dobrze, może być użyteczny dla kogoś

wybierz * z tabeli_tabej, gdzie kolumna_kolumny :: tekst jest DOWOLNY (ARRAY ['% text_to_search%' :: text]);

Dave Kraczo
źródło