How do I write a query in SQL with an exclusive? - postgresql

Using the SELECT COUNT and BETWEEN operators I also need to exclude two integers.
SELECT COUNT(*)
FROM purchases
WHERE user_id BETWEEN 10 AND 50
I need to exclude 20 and 30. I’ve tried using NOT, NOT IN and NULL. What am I missing?

Just add another condition:
SELECT COUNT(*)
FROM purchases
WHERE user_id BETWEEN 10 AND 50
AND user_id NOT IN (20,30);

Adding "AND user_id NOT IN (20,30)" doesn't work? Could try just adding a "user_id <> 20 AND user_id <> 30"

Related

count(1) and distinct behaviour in postgres

Imagine a table:
name age
John 20
Sam 60
Dave 30
John 15
I want to check count of distinct names, I query the table like so:
SELECT COUNT(1), DISTINCT(name)
FROM table
GROUP BY 2
But I get:
ERROR: syntax error at or near "DISTINCT"
Position: 18
But when I use:
SELECT DISTINCT(name), COUNT(1)
FROM table
GROUP BY 1
I do get what's expected:
John 2
Sam 1
Dave 1
Is there a reason why the first query is not working or am I making a mistake somewhere?
The distinct here is not required. GROUP BY means 'group by a distinct set of values'
so
SELECT COUNT(*), name
FROM table
GROUP BY name;
Will give you the result I think you want.

Postgres: How to count records with ranged condition?

Working with table with columns:
(PK)sales_log_id
user_id
created_at
With sales_log_id to represent transaction activities for users.
I have been able to query how many users have x amount of transactions.
Now I would like to find out how many users have eg. > 10 AND < 20 transactions in a certain period of time.
Being new with databases and Postgres, I'm learning that you can do a query and another query with the previous result (subquery). So I tried to query first how many users are having < 30 transactions in June and later query the result for users having > 10 transactions.
SELECT COUNT(DISTINCT t.user_id) usercounter
FROM (
SELECT user_id, created_at, sales_log_id
FROM sales_log
WHERE created_at BETWEEN
'2019-06-01' AND '2019-06-30'
GROUP BY user_id, created_at, sales_log_id
HAVING COUNT (sales_log_id) <30
)t
GROUP BY t.user_id
HAVING COUNT (t.sales_log.id) >10;
But it produced an error
ERROR: missing FROM-clause entry for table "sales_log"
LINE 11: HAVING COUNT (t.sales_log.id) >10;
^
SQL state: 42P01
Character: 359
Can anyone please provide the correct way to do this?
I think it is as simple as
SELECT count(*)
FROM (
SELECT user_id, COUNT(*)
FROM sales_log
WHERE created_at BETWEEN '2019-06-01' AND '2019-06-30'
GROUP BY user_id
HAVING COUNT (sales_log_id) BETWEEN 11 AND 29
) AS q;
Only add DISTINCT to a query if you really need it.
It is just one word, but it can have a big performance penalty.

How to select the highest value and subtract the lower values from Postgresql nested query

This is what I'm trying to achieve - say I have an integer column with people's ages for instance, I want to select the highest age and get it's difference with the other selected ages. So if I do:
SELECT ages FROM people
ORDER BY ages DESC
And get 30 25 20 15 10 for example, I'd like to do another SELECT that will perform 30-30, 30-25, 30-20, 30-15, 30-10
SELECT --how do I perform that here?
FROM (
SELECT ages FROM peoeple
ORDER BY ages DESC
)foo
How can I achieve this?
Use a subquery that returns the max age:
select (select max(age) from people) - age
from people
order by 1 -- ordering is optional, but it seems you want data in this order
btw, age is a better name for someone's age than ages.

How to aggregate on first value in postgres sql?

In this postgres query
SELECT
q.*,
q.user_id = 1 mine,
first(u.username) username,
sum(case when v.answer=0 then 1 else 0 end) no_count,
sum(case when v.answer=1 then 1 else 0 end) yes_count
FROM question q
JOIN "user" u ON q.user_id=u.id
JOIN vote v ON v.question_id=q.id
GROUP BY q.id
ORDER BY q.date_created desc
LIMIT 20
OFFSET 0
It says I need an aggregate on username. In this case, I am getting questions, and each question is created by some user. I join on votes, but group by the question id, so before grouping the username field will be the same for each unique question. So that means when aggregating, really I can pick any value since it's all the same. However I can't find any aggregate function to use. I tried random, first, last, any, but none work or even defined.
Does anyone know how to handle this?
Ok, so problem is that sql engine doesn't know that username will be always the same. In other words it can't tell relation one-to-one from one-to-many between guestions and users. You could use string_agg() with DISTINCT like string_agg(DISTINCT u.username, ','::text). What that functions does is it's aggragetes text values into one big string seperated by specified delimiter (in my case comma). When you add DISTINCT it takes only unique values. Since you've said theres always only one username per question the output will be that single value.
The whole query:
SELECT
q.*,
q.user_id = 1 mine,
string_agg(DISTINCT u.username, ','::text) username,
sum(case when v.answer=0 then 1 else 0 end) no_count,
sum(case when v.answer=1 then 1 else 0 end) yes_count
FROM question q
JOIN "user" u ON q.user_id=u.id
JOIN vote v ON v.question_id=q.id
GROUP BY q.id
ORDER BY q.date_created desc
LIMIT 20;
Footnote: I dropped the OFFSET 0 because it's default value for LIMIT.
From the box postgresql do not allow or cant do such operations, but there is workaround.
You can extend aggregate functions First/Last by this method: https://wiki.postgresql.org/wiki/First/last_(aggregate)
There is plugin and portable sql version for postgresql.

distinct key word only for one column

I'm using postgresql as my database, I'm stuck with getting desired results with a query,
what I have in my table is something like following,
nid date_start date_end
1 20 25
1 20 25
2 23 26
2 23 26
what I want is following
nid date_start date_end
1 20 25
2 23 26
for that I used SELECT DISTINCT nid,date_start,date_end from table_1 but this result duplicate entries, how can I get distinct nid s with corresponding date_start and date_end?
can anyone help me with this?
Thanks a lot!
Based on your sample data and sample output, your query should work fine. I'll assume your sample input/output is not accurate.
If you want to get distinct values of a certain column, along with values from other corresponding columns, then you need to determine WHICH value from the corresponding columns to display (your question and query would otherwise not make sense). For this you need to use aggregates and group by. For example:
SELECT
nid,
MAX(date_start),
MAX(date_end)
FROM
table_1
GROUP BY
nid
That query should work unless you are selecting more columns.
Or maybe you are getting the same nid with a different start and/or end date
Try distinct on:
select distinct on (col1) col1, col2 from table;
DISTINCT can't result in duplicate entries - that's what it does... removed duplicates.
Is your posted data is incorrect? Exactly what are your data and output?