How can I query NOT IN from an array? - sql

const friendIds = friends.rows.map((friend) => friend.friend_id);
console.log("list", friendIds); //list [ 50, 51 ]
const users = await pool.query(
"SELECT * FROM super_user WHERE user_id NOT IN(ARRAY[$1])",
[friendIds]
);
I want to query all users where the user_id does not equal any of the items in the array.
for some reason, even chat GPT is unable to give me a good solution

you can use <> ALL()
SELECT *
FROM super_user
WHERE user_id <> ALL(ARRAY[$1])

By Using ALL
SELECT * FROM
super_user
WHERE user_id != ALL(ARRAY[$1])
By Using ANY
SELECT * FROM
super_user
WHERE NOT (user_id = ANY(ARRAY[$1]))

In the doc, there's 9.24. Row and Array Comparisons showing examples of this: online demo
SELECT * FROM super_user WHERE not user_id = SOME(ARRAY[$1]);
SELECT * FROM super_user WHERE user_id <> ALL(ARRAY[$1]);
In 9.19. Array Functions and Operators you can find it's also possible to just unnest() the array and compare to the resulting list of elements or see if the array_position() of your element is null:
SELECT * FROM super_user WHERE not user_id in (select * from unnest(ARRAY[$1]));
SELECT * FROM super_user WHERE array_position(ARRAY[$1], user_id) is null;
Good to know what happens if you get a null on either side:
select null=any(array[1, 2]),--null, not false
null=any(array[null,2]),--null, even though it's technically there
1 =any(array[null,2]),--null, not false
1 =any(array[null,1]);--true, even though there was a null to compare to

Related

How do I write a query to reference two keys and two values?

I am trying to write a query in Google BigQuery that pulls two keys and two values. The query should be: count distinct psuedo user IDs from one table where event_params.key = result and event_params.key = confirmation number (and is not null), and event_params.value.string_value = success. This has already been unnested. I'm SUPER new to SQL, so please dumb down any answers.
SELECT
*
FROM
`table_name`,
UNNEST(event_params) AS params
WHERE
(stream_id = '1168190076'
OR stream_id = '1168201031')
AND params.key = 'result'
AND params.value.string_value IN ('success',
'SUCCESS')
AND params.key = 'confirmationNumber' NOT NULL
I keep getting errors, and when I don't get errors, my numbers are off by a lot! I'm not sure where to go next.
Below is for BigQuery Standard SQL
#standardSQL
SELECT *
FROM `project.dataset.table`
WHERE stream_id IN ('1168190076', '1168201031')
AND 2 = (
SELECT COUNT(1)
FROM UNNEST(event_params) param
WHERE (
param.key = 'result' AND
LOWER(param.value.string_value) = 'success'
) OR (
param.key = 'confirmationNumber' AND
NOT param.value.string_value IS NULL
)
)
I suspect that you want something more like this:
SELECT t.*
FROM `table_name`t
UNNEST(event_params) AS params
WHERE t.stream_id IN ('1168190076', '1168201031') AND
EXISTS (SELECT 1
FROM UNNEST(t.event_params) p
WHERE p.key = 'result' AND
p.value.string_value IN ('success', 'SUCCESS')
) AND
EXISTS (SELECT 1
FROM UNNEST(t.event_params) p
WHERE p.key = 'confirmationNumber'
);
That is, test each parameter independently. You don't need to unnest the result for the result set -- unless you really want to, of course.
I don't know what the lingering NOT NULL is for in your query, so I'm ignoring it. You might want to check the value, however.

Check if all rows are the same

I have a select query that returns multiple rows, and I want to check if all rows are the same. So something like this:
anything_other_than(123) in (select id from foo)
So, if select id from foo returns 111,222,123,333 the statement above is false, and if select id from foo returns 123,123,123 it's true. How can I achieve this?
A simple solution is to use the = ALL operator:
SELECT 123 = ALL (SELECT id FROM foo);
This solution also stop scanning the result as soon as the first non-matching value is found.
Another option is to use EXISTS with a where condition:
select not exists (select *
from the_table
where id <> 123);
Run this:
select count(distinct id) = 1 and count(*) > 1 from foo;
count(distinct id) will return 1 if all the rows are the same
and count(*) will return the total number of rows.
If this returns true then you have more than 1 rows and all the rows are the same.
You can use something like this -
select x, IF(x > 1, "FALSE", "TRUE") from
(SELECT count(distinct(A.id)) as x FROM foo as A) as B;
Do refer this https://www.w3schools.com/sql/func_mysql_if.asp

Recursive SQL query only returning single reference instead of recursive references

I have a DB table
id (INT, NOT NULL)
username (NVARCHAR, NOT NULL)
holiday_replacement (INT, NULL)
The holiday_replacement is either NULL or it references a value in the id field.
Now, it would be trivial to determine for whom a specified id was the holiday_replacement, but to complicate this query the holiday_replacement may be chained.
In simpler terms, a user may have a holiday_replacement who themselves has a holiday_replacement.
In such a case the query should return a list of all users in this 'holiday replacement graph'.
Currently I have
WITH user_graph AS (
SELECT
*
FROM
table_name
WHERE
holiday_replacement = #current_user_id
UNION ALL
SELECT
tn.*
FROM
table_name tn
JOIN user_graph ug ON ug.holiday_replacement = tn.id
)
SELECT
id
FROM
user_graph
However, this query only returns those users who have directly referenced #current_user_id as their holiday_replacement and doesn't consider any other users who should also be returned on account of this chaining.
For example, if I have the following 3 users:
id = 1, username = 'user_1', holiday_replacement = NULL
id = 2, username = 'user_2', holiday_replacement = 1
id = 3, username = 'user_3', holiday_replacement = 2
then for #current_user_id = 1, the query should return
id
---
2
3
but presently it only considers that directly referenced user and returns
id
---
2
I just can't wrap my head around what I need to change. Can anyone help?
use below code
WITH user_graph AS (
SELECT
*
FROM
table_name
WHERE
holiday_replacement = #current_user_id
UNION ALL
SELECT
tn.*
FROM
table_name tn
JOIN user_graph ug ON ug.id =tn.holiday_replacement
)
SELECT
id FROM
user_graph

select specific records using IN

I need to select records that has ID = 10,23,30 so I wrote this SQL
Select * from mytable where position(id in '10,23,30') > 0
But the problem I get additional records where ID = 1 and 2
Any ideas how to select only what I need ?
No need for position, just do IN:
Select * from mytable
where id in (10,23,30)
Use IN operator:
Select * from mytable where id in (10,23,30)

unnest() subquery that returns an array?

I've encountered a rather unintuitive behaviour while unnesting array results returned FROM sub-SELECT.
SELECT unnest(c).*
FROM (SELECT chat_messages[0 : array_length(chat_messages, 1)]
FROM Chats WHERE chat_id = 2) c
This was my original query. Postgres doens't like it:
function unnest(record) does not exist
But this seemingly equivalent query works:
SELECT *
FROM unnest((SELECT chat_messages[0 : array_length(chat_messages, 1)]
FROM Chats WHERE chat_id = 2)) c
This query doesn't work either with the same error message:
SELECT *
FROM (SELECT chat_messages[0 : array_length(chat_messages, 1)]
FROM Chats WHERE chat_id = 2) c,
unnest(c) u
I'm pretty sure I'm missing something here. Why such behaviour? And how come subquery returns record type when it's defined composite type?
In the first and third queries c is formally a set of rows (of pseudo-type record), so you cannot unnest(c). You should use a value instead (I skipped slice as irrelevant):
Query #1:
SELECT (unnest(val)).*
FROM (
SELECT chat_messages
FROM Chats WHERE chat_id = 2
) c(val);
-- or
SELECT (unnest(val)).*
FROM (
SELECT chat_messages val
FROM Chats WHERE chat_id = 2
) c;
Query #3:
SELECT *
FROM (
SELECT chat_messages
FROM Chats WHERE chat_id = 2
) c(val),
unnest(val) u;
-- or
SELECT *
FROM (
SELECT chat_messages val
FROM Chats WHERE chat_id = 2
) c,
unnest(val) u;
In query #2 you extract a value by using additional brackets, so the result is not a row but a value (an array in this case). This query will raise an error if the inner query returns more than one row.