I have a POSTGRES field with 2 fields - integer arrayfield and integer field.
CREATE TABLE test.public.polls (
"id" serial NOT NULL,
field_1 _int4,
field_2 int4 NOT NULL,
PRIMARY KEY ("id")
);
and the values are
1) Now I need to check if any of the field value {1,2,3} is in the field_1
something like this -
select * from test.public.polls
where field_1 = ANY ('{1,2,3}'::int[])
but this throws an error
operator does not exist: integer[] = integer
2) Need to check if any of the id values = {2,3,4} is in the field_1
select * from test.public.polls
where field_1 = array(id)
not sure what should be the syntax for this.
Since your field_1 seems to be an array then following should work (this is called overlapping):
select *
from yourtable
where field_1 && '{1,2,3}'::int[]
For the second part it seems like you'd like to aggregate id column and check whether any value from the aggregated set exists within field_1:
select *
from yourtable
where field_1 && (select array_agg(id) from yourtable)
Use overlap operator &&
SELECT *
FROM polls
WHERE '{1,2,3}' && field_1
Here is a SQLFiddle
Related
I have an array with some ids on the front-end and I'm writing a query to check if I can find any user with a user_id inside the array, the table is very simple:
CREATE TABLE user_accounts (
user_id UUID NOT NULL REFERENCES users (id) ON DELETE CASCADE,
name TEXT,
connector_type connector_type_enum NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL
);
The array on the front-end is something like ["328hdgyas78g2", "3adhdayas7453"]
and here's the query:
SELECT *
FROM user_accounts
WHERE user_id IN $1
of course there's a syntax error, I have tried the following:
SELECT *
FROM user_accounts
WHERE user_id = ANY(ARRAY["328hdgyas78g2", "3adhdayas7453"])
but I get the following error:
ERROR: column "328hdgyas78g2" does not exist
How can I fix the query?
That's because the " is used to reference a column or table name. To reference a string you use the single '
You have a couple of options there
WHERE user_id = ANY(ARRAY['328hdgyas78g2', '3adhdayas7453'])
or
WHERE user_id = ANY('{328hdgyas78g2,3adhdayas7453}')
Also, good reference is this
I have a simple table defined in Postgres, where I'm using LTREE, but some rows can have empty paths:
CREATE TABLE films (
id serial PRIMARY KEY,
title varchar(40) NOT NULL,
path ltree DEFAULT NULL
);
If I insert the following values into the table,
INSERT INTO films (title, path)
VALUES ('first', 'A'),('second', 'A.B'),('third', NULL);
then try to select the rows with empty paths,
SELECT * FROM films WHERE path=NULL;
I get empty rows:
id | title | path
----+-------+------
(0 rows)
How should I modify the query to return rows with empty paths? Thanks!
The result of comparison operation with at least one operand is NULL always returns NULL. Thus your predicate where path = null always returns null, but the to select a row the expression must return True. Use instead:
SELECT * FROM films WHERE path is NULL;
I want the rows in which there is at least one column with a null value. I've tried to use a row expression like:
SELECT *
FROM <table>
WHERE <table> IS NULL
But it does not work. Is my query incorrect or?
PS I am using version 13.4
You can reference the table alias in the WHERE clause. The condition where the_table is not null would return the rows where all columns are not null.
The opposite of that (where at least one column is null) can be achieved by negating the expression:
select *
from the_table
where not (the_table is not null);
Looks a bit strange, but it's not the same as the_table is null - which is never true, as the reference to the table (alias) refers to an existing row. And if a row exists the the "whole row" can't be null.
This:
with the_table (col1, col2, col3) as (
values
(1,null,null),
(null,2,null),
(null,3,4),
(5,6,7)
)
select *
from the_table
where not (the_table is not null);
returns:
col1 | col2 | col3
-----+------+-----
1 | |
| 2 |
| 3 | 4
to check if the value is not null, you use the IS NOT NULL operator
value IS NOT NULL
The expression returns true if the value is NULL or false if it is not.
You need to mention your column name in the search.
SELECT * FROM <table_name> WHERE <column_name> IS NULL;
For more than one columns:
SELECT * FROM <table_name> WHERE <column1_name> IS NULL OR <column2_name> IS NULL;
I would like to create a function that returns a column of a table as an integer array.
In other words, how can I transfrom the result of SELECT id FROM mytable to integer[] ?
You can do:
SELECT ARRAY(SELECT id FROM mytable)
Or:
SELECT array_agg(id) FROM mytable
I'm using PostgreSQL 9.0 and I have a table with just an artificial key (auto-incrementing sequence) and another unique key. (Yes, there is a reason for this table. :)) I want to look up an ID by the other key or, if it doesn't exist, insert it:
SELECT id
FROM mytable
WHERE other_key = 'SOMETHING'
Then, if no match:
INSERT INTO mytable (other_key)
VALUES ('SOMETHING')
RETURNING id
The question: is it possible to save a round-trip to the DB by doing both of these in one statement? I can insert the row if it doesn't exist like this:
INSERT INTO mytable (other_key)
SELECT 'SOMETHING'
WHERE NOT EXISTS (SELECT * FROM mytable WHERE other_key = 'SOMETHING')
RETURNING id
... but that doesn't give the ID of an existing row. Any ideas? There is a unique constraint on other_key, if that helps.
Have you tried to union it?
Edit - this requires Postgres 9.1:
create table mytable (id serial primary key, other_key varchar not null unique);
WITH new_row AS (
INSERT INTO mytable (other_key)
SELECT 'SOMETHING'
WHERE NOT EXISTS (SELECT * FROM mytable WHERE other_key = 'SOMETHING')
RETURNING *
)
SELECT * FROM new_row
UNION
SELECT * FROM mytable WHERE other_key = 'SOMETHING';
results in:
id | other_key
----+-----------
1 | SOMETHING
(1 row)
No, there is no special SQL syntax that allows you to do select or insert. You can do what Ilia mentions and create a sproc, which means it will not do a round trip fromt he client to server, but it will still result in two queries (three actually, if you count the sproc itself).
using 9.5 i successfully tried this
based on Denis de Bernardy's answer
only 1 parameter
no union
no stored procedure
atomic, thus no concurrency problems (i think...)
The Query:
WITH neworexisting AS (
INSERT INTO mytable(other_key) VALUES('hello 2')
ON CONFLICT(other_key) DO UPDATE SET existed=true -- need some update to return sth
RETURNING *
)
SELECT * FROM neworexisting
first call:
id|other_key|created |existed|
--|---------|-------------------|-------|
6|hello 1 |2019-09-11 11:39:29|false |
second call:
id|other_key|created |existed|
--|---------|-------------------|-------|
6|hello 1 |2019-09-11 11:39:29|true |
First create your table ;-)
CREATE TABLE mytable (
id serial NOT NULL,
other_key text NOT NULL,
created timestamptz NOT NULL DEFAULT now(),
existed bool NOT NULL DEFAULT false,
CONSTRAINT mytable_pk PRIMARY KEY (id),
CONSTRAINT mytable_uniq UNIQUE (other_key) --needed for on conflict
);
you can use a stored procedure
IF (SELECT id FROM mytable WHERE other_key = 'SOMETHING' LIMIT 1) < 0 THEN
INSERT INTO mytable (other_key) VALUES ('SOMETHING')
END IF
I have an alternative to Denis answer, that I think is less database-intensive, although a bit more complex:
create table mytable (id serial primary key, other_key varchar not null unique);
WITH table_sel AS (
SELECT id
FROM mytable
WHERE other_key = 'test'
UNION
SELECT NULL AS id
ORDER BY id NULLS LAST
LIMIT 1
), table_ins AS (
INSERT INTO mytable (id, other_key)
SELECT
COALESCE(id, NEXTVAL('mytable_id_seq'::REGCLASS)),
'test'
FROM table_sel
ON CONFLICT (id) DO NOTHING
RETURNING id
)
SELECT * FROM table_ins
UNION ALL
SELECT * FROM table_sel
WHERE id IS NOT NULL;
In table_sel CTE I'm looking for the right row. If I don't find it, I assure that table_sel returns at least one row, with a union with a SELECT NULL.
In table_ins CTE I try to insert the same row I was looking for earlier. COALESCE(id, NEXTVAL('mytable_id_seq'::REGCLASS)) is saying: id could be defined, if so, use it; whereas if id is null, increment the sequence on id and use this new value to insert a row. The ON CONFLICT clause assure
that if id is already in mytable I don't insert anything.
At the end I put everything together with a UNION between table_ins and table_sel, so that I'm sure to take my sweet id value and execute both CTE.
This query needs to search for the value other_key only once, and is a "search this value" not a "check if this value not exists in the table", that is very heavy; in Denis alternative you use other_key in both types of searches. In my query you "check if a value not exists" only on id that is a integer primary key, that, for construction, is fast.
Minor tweak a decade late to Denis's excellent answer:
-- Create the table with a unique constraint
CREATE TABLE mytable (
id serial PRIMARY KEY
, other_key varchar NOT NULL UNIQUE
);
WITH new_row AS (
-- Only insert when we don't find anything, avoiding a table lock if
-- possible.
INSERT INTO mytable ( other_key )
SELECT 'SOMETHING'
WHERE NOT EXISTS (
SELECT *
FROM mytable
WHERE other_key = 'SOMETHING'
)
RETURNING *
)
(
-- This comes first in the UNION ALL since it'll almost certainly be
-- in the query cache. Marginally slower for the insert case, but also
-- marginally faster for the much more common read-only case.
SELECT *
FROM mytable
WHERE other_key = 'SOMETHING'
-- Don't check for duplicates to be removed
UNION ALL
-- If we reach this point in iteration, we needed to do the INSERT and
-- lock after all.
SELECT *
FROM new_row
) LIMIT 1 -- Just return whatever comes first in the results and allow
-- the query engine to cut processing short for the INSERT
-- calculation.
;
The UNION ALL tells the planner it doesn't have to collect results for de-duplication. The LIMIT 1 at the end allows the planner to short-circuit further processing/iteration once it knows there's an answer available.
NOTE: There is a race condition present here and in the original answer. If the entry does not already exist, the INSERT will fail with a unique constraint violation. The error can be suppressed with ON CONFLICT DO NOTHING, but the query will return an empty set instead of the new row. This is a difficult problem because getting that info from another transaction would violate the I in ACID.