I am trying to select all the elements where x_id=1 but there will be multiple rows for that result with the same user_id and I just want it to show one result for each user id (instead of multiple). How would I be able to do this in SQL im completely lost?
Table:
a
id | x_id | user_id
SELECT DISTINCT user_id FROM table WHERE x_id = 1;
select distinct user_id from a where x_id = 1;
SELECT a.user_id
FROM a a
WHERE a.x_id = 1
GROUP BY a.user_id
-- or --
SELECT DISTINCT a.user_id
FROM a a
WHERE a.x_id = 1
These return an equivalent result set. My personal preference is to use the GROUP BY, because I sometimes want to return a count of the number of rows, or use some other aggregate function, which I can't do with the DISTINCT.
Related
I have two related tables as follows :
USERS
user_id <\PK>
USERACTIONS
user_action_id <\PK>
user_id <\FK>
user_action <\int>
Whenever user performs an action, there is a new insertion in "useractions" table. I need a query to fetch those USERACTION rows where user performed only particular set of actions say (1,2) but not (3,4).
So I have a query like -
select * from USERACTIONS where (1,2) in(select user_action from USERACTIONS where user_id=100) and user_id=100;
Problem is the above query doesn't work as supplying (1,2) expects subquery also to return two columns which is understandable. This is the error I get -
ERROR: subquery has too few columns
Giving a single value say (1) or (2) works perfectly. I want to know if there is any way I can use the same query and compare the subquery's result with multiple values? I prefer the same query because the case demonstrated here is just a part of a large query.
Please note the query should not list users who performed (1,2,3,4) those who performed only (1,2) should be listed and also user_action values can be any random integer.
Any alternate queries are welcome but would prefer changes in the same query. Thanks in advance.
try this:
SELECT USERS.user_id, USERACTIONS.user_action
FROM USERACTIONS
LEFT JOIN USERS ON USERS.user_id = USERACTIONS.user_id where USERACTIONS.user_action in (1,2);
This Works for your query.
You add the numbers to the in Clause
SELECT a.user_id
FROM
(SELECT DISTINCT user_id
from
USERACTIONS
WHERE user_action
IN (1,2)) a
INNER JOIN
(SELECT DISTINCT user_id
from
USERACTIONS
WHERE user_action
NOT IN (1,2)) b
ON a.user_id <> b.user_id
;
CREATE TABLE USERACTIONS (id INT NOT NULL AUTO_INCREMENT
, PRIMARY KEY(id)
, user_action INT
, user_id INT
);
INSERT USERACTIONS VALUES (NULL,1,100),(NULL,2,100),(NULL,3,100), (NULL,1,101),(NULL,2,101);
✓
✓
SELECT a.user_id
FROM
(SELECT DISTINCT user_id
from
USERACTIONS
WHERE user_action
IN (1,2)) a
INNER JOIN
(SELECT DISTINCT user_id
from
USERACTIONS
WHERE user_action
NOT IN (1,2)) b
ON a.user_id <> b.user_id
;
| user_id |
| ------: |
| 101 |
db<>fiddle here
I see typical SO answers that aren't answering OP's question, but rather trying to steer them in a different direction. I know this is old, but if anyone stumbles upon this, I believe this will be more helpful.
I too have a large, enterprise solution where the WHERE check is MUCH more performant in a subquery than using a JOIN.
You can set a variable in your WHERE clause and use it afterwards. I am currently trying to find a better way to do this without setting a variable, but something like this works:
SELECT * FROM USERACTIONS
WHERE
( #useraction =
(select user_action from USERACTIONS where user_id=100 LIMIT 1)
= 1
OR #useraction = 2)
AND user_id=100;
What you are doing is creating a variable in your WHERE clause, setting that variable, then using it later. This is encapsulated, so it can match either one of the conditions.
I have a table "users" which has multiple columns in which column "status" has multiple values like 1,0,3,2,4. There is column "user_id" which doesn't contain unique values since, this is foreign key of another table called "user_master".
so here in "users" table we have multiple values of the one user.
So, Here is my actual query is that i would like to write a sql query to find users has only one entry in table "users" with particular status value.
For e.g. I would like to fetch all such users with status=2 and their entry in table is not more than 1. Like if user has multiple entries with status 2,1,4 in table which should not be return in query.
It should yield those users which has only one entry in table and which is of status = 2
That must be what you use:
Select count(u.user_id) AS cnt, u.*
from user u
where u.status = 2
group by u.user_id, u.status
having cnt = 1;
WITH tmp AS(
SELECT Stud_Id,COUNT(*) AS 'Count' FROM Student_tbl GROUP BY Stud_Id
)
SELECT * FROM tmp WHERE Count = 1 AND Status = 2
You have to add field in GROUP BY Clause whichever you want to use in SELECT clause.
I have researched it and found answer for it.
And query goes like this.
select count(id) as cnt,
user_id,status from users
group by user_id
having cnt < 2 and status=2
First it will group the things having count less than 2 and then which will check for status.
I have three tables:
user: id, name
keyword: id, name
userkeyword: id, user_id, keyword_id
I want to execute query in following way:
Display those users whose keyword/s are matched with the login user's
keywords. In the order of maximum number of keyword matched user
should display first
e.g : If userA having 4 matched keywords, userB having 8, userC having 1, userD having 6 then the result should be in the order of,
userB
userD
userA
userC
For that I have done with this query (assume login user's id is 1):
select *
from user
where id IN (
select user_id
from userkeywords
where keyword_id IN (
select keyword_id
from userkeywords
where user_id=1)
group by user_id
order by count(keyword_id) desc)
AND id != 1
Here the result is getting perfect but the order is not correct. I have merged two queries in following manner"
select *
from user
where id IN (?)
AND id!=1
+
select user_id
from userkeywords
where keyword_id IN (
select keyword_id
from userkeywords
where user_id=1)
group by user_id
order by count(keyword_id) desc
Second query returns user_id in correct order but when I merged both queries, order was changed (wrong).
Hope I have mentioned my query properly with enough detail.
A subquery returns an unordered set, so the order by in a subquery only matters for its limit clause, if there is any. Any database other than MySQL would give an error message for a purely decorative sort order.
There's no way to sort on a column that only exists in the where clause. You'd have to rewrite the query. One option is to replace your in conditions with joins:
select uk2.name
from userkeywords uk1
join userkeywords uk2
on uk1.keyword_id = uk2.keyword_id
and uk1.user_id <> uk2.user_id
join user u2
on u2.id = uk2.user_id
where uk1.user_id = 1
group by
uk2.name
order by
count(*) desc
This should do it.
select uk.user_id, u.name
from userkeywords uk
left join user u on u.id = uk.user_id
where uk.keyword_id IN (
select keyword_id
from userkeywords
where user_id=1)
group by uk.user_id
order by count(uk.keyword_id) desc) AND uk.user_id != 1
Also, JOIN provides better performance.
I would use an inner join to select the correct rows:
SELECT *
FROM user
INNER JOIN (
SELECT * FROM userkeyword
WHERE keyword_id IN (
SELECT keyword_id
FROM userkeyword
WHERE user_id=1
)
) uk
ON user.id = uk.user_id
GROUP BY u.id
ORDER BY count(*) DESC;
I have a MySQL table where I have a certain id as a foreign key coming from another table. This id is not unique to this table so I can have many records holding the same id.
I need to find out which ids are seen the least amount of times in this table and pull up a list containing them.
For example, if I have 5 records with id=1, 3 records with id=2 and 3 records with id=3, I want to pull up only ids 2 & 3. However, the data in the table changes quite often so I don't know what that minimum value is going to be at any given moment. The task is quite trivial if I use two queries but I'm trying to do it with just one. Here's what I have:
SELECT id
FROM table
GROUP BY id
HAVING COUNT(*) = MIN(SELECT COUNT(*) FROM table GROUP BY id)
If I substitute COUNT(*) = 3, then the results come up but using the query above gives me an error that MIN is not used properly. Any tips?
I would try with:
SELECT id
FROM table
GROUP BY id
HAVING COUNT(*) = (SELECT COUNT(*) FROM table GROUP BY id ORDER BY COUNT(*) LIMIT 1);
This gets the minimum selecting the first row from the set of counts in ascendent order.
You need a double select in the having clause:
SELECT id
FROM table
GROUP BY id
HAVING COUNT(*) = (SELECT MIN(cnt) FROM (SELECT COUNT(*) as cnt FROM table GROUP BY id) t);
The MIN() aggregate function is suposed to take a column, not a query. So, I see two ways to solve this:
To properly write the subquery, or
To use temp variables
First alternative:
select id
from yourTable
group by id
having count(id) = (
select min(c) from (
select count(*) as c from yourTable group by id
) as a
)
Second alternative:
set #minCount = (
select min(c) from (
select count(*) as c from yourTable group by id
) as a
);
select id
from yourTable
group by id
having count(*) = #minCount;
You need to GROUP BY to produce a set of grouped values and additional select to get the MIN value from that group, only then you can match it against having
SELECT * FROM table GROUP BY id
HAVING COUNT(*) =
(SELECT MIN(X.CNT) AS M FROM(SELECT COUNT(*) CNT FROM table GROUP BY id) AS X)
I have three tables: a_survey, b_survey and c_survey. Each of these tables have a column_name "user_id". What I want to do is count the actual posted surveys and return that value in a single row. So, if there was found one record with the matching user_id for each of these tables, the count would return 3.
Here's what I've tried:
select count(user_id) AS total_of_surveys
FROM a.survey, b.survey, c.survey
WHERE user_id = 3;
but I'm getting error:
Column 'user_id' in field list is ambiguous
Thanks in advance!
select sum(count(a.survey.user_id)+count(b.survey.user_id)+count(c.survey.user_id)) AS total_of_surveys
FROM a.survey, b.survey, c.survey
WHERE user_id = 3;
What you have tried was a cartesian plan it will multiply the result by the quantity of registries on each table.
The right way to do what you want is to join (with left join) or 'UNION' the tables like:
select count(user_id) from
(select user_id from a_survey where user_id = 3 UNION ALL
select user_id from b_survey where user_id = 3 UNION ALL
select user_id from c_survey where user_id = 3) tables
You will need to count each table seperately and sum it together. You can do this with one (ugly) query if you want. Something like this should work:
Select (select count(user_id) FROM a.survey WHERE user_id = 3) + (select count(user_id) FROM b.survey WHERE user_id = 3) + (select count(user_id) FROM c.survey WHERE user_id = 3) as total_of_surveys;