Show rows with at least one occurrence in a relation table? - sql

I have the following table schema:
user (id, name, alias, password, active, mail, age)
comment(id, news(FK), user(FK), text, date)
new_cat(news(FK), category(FK))
I'm trying to select all the users who have commented on AT LEAST one new of EVERY category.
This is what I'm trying without any success:
SELECT * FROM user AS u, comment AS c
WHERE u.id = c.user AND c.news IN (SELECT news FROM new_cat);
I believe this is not iterating properly and checking for EVERY category and just checks if the condition applies just on one category.
How can I properly do this?

Join the tables, group by user and set the condition in the HAVING clause.
If there is a category table where you store all the categories:
SELECT u.*
FROM user u
INNER JOIN comment c ON c.user = u.id
INNER JOIN new_cat n ON n.news = c.news
GROUP BY u.id
HAVING COUNT(DISTINCT n.category) = (SELECT COUNT(*) FROM category);

Related

Select name from SQL column

I am trying to select the names (along with the rest of the information on the table such as data, time, lesson) of each user that is inside a users table. The names I'm trying to select are the ones that are on the same row as a particular teacherID. However when I run this code I'm getting the same name for all records, when I should be getting two different ones.
SELECT FName, SName, bookedLessons.bookedHour,
bookedLessons.bookedDate, bookedLessons.lesson
FROM users JOIN bookedLessons
WHERE teacherID = 11
AND users.userID = (SELECT userID FROM bookedLessons WHERE teacherID = 11)
Your join needs an ON clause but not the subquery in the WHERE clause:
SELECT u.FName, u.SName, b.bookedHour, b.bookedDate, b.lesson
FROM bookedLessons b INNER JOIN users u
ON u.userID = b.userID
WHERE b.teacherID = 11

Join with count

I need to write SQL query like:
Show all countries with more than 1000 users, sorted by user count.
The country with the most users should be at the top.
I have tables:
● Table users (id, email, citizenship_country_id)
● Table countries (id, name, iso)
Users with columns: id, email, citizenship_country_id
Countries with columns: id, name, iso
SELECT countries.name,
Count(users.citiizenship_country_id) AS W1
FROM countries
LEFT JOIN users ON countries.id = users.citizenship_country_id
GROUP BY users.citiizenship_country_id, countries.name
HAVING ((([users].[citiizenship_country_id])>2));
But this does not work - I get an empty result set.
Could you please tell me what I'm doing wrong?
A LEFT JOIN is superfluous for this purpose. To have 1000 users, you need at least one match:
SELECT c.name, Count(*) AS W1
FROM countries c JOIN
users u
ON c.id = u.citizenship_country_id
GROUP BY c.name
HAVING COUNT(*) > 1000;
Notice that table aliases also make the query easier to write and to read.
Group by country name and use HAVING Count(u.citiizenship_country_id)>1000, it filters rows after aggregation:
SELECT c.name,
Count(u.citiizenship_country_id) AS W1
FROM countries c
INNER JOIN users u ON c.id = u.citizenship_country_id
GROUP BY c.name
HAVING Count(u.citiizenship_country_id)>1000
ORDER BY W1 desc --Order top counts first
;
As #GordonLinoff pointed, you can use INNER JOIN instead of LEFT JOIN, because anyway this query does not return counries without users and INNER JOIN performs better because no need to pass not joined records to the aggregation.

SQL JOIN COUNT and SELECT in Rails 4

I am new to SQL and trying to join 2 tables to add a count :
First Table: Slot, Second Table : Reservation (with column slot_id), so to count the reservations associated to a given slot
group_by slots.id
count reservations.id
I would like to join the user of the slot (user_id column in Slot table) with joins(:user), with his email, but I can't use this select because of the group_by
select('slots.*, count(reservations.id) as res_count, users.email as email')
How can I join the user with his email and still perform the count?
You haven't mentioned anything about the relationship between user and slot, but assuming each slot can only have one user, you should just add the email to the group by statement also:
select
s.id as slot_id,
u.email,
count(reservation.id) as num_reservations
from Slot s
left join Reservation r
on s.reservation_id = r.id --assuming this is the key
left join Users u
on s.user_id = u.id
group_by slot.id, u.email;

Getting data having only same values in all rows in DB2

I have 2 tables in DB2:
1) users ==> basic user details
2) details ==> more user details
The "details" table has columns named ssn, company and super_company. The company and super_company column can have multiple values for the same SSN.
Problem: I am trying to fetch only the users which has same super_company for the ssn.
I need username,ssn and company_id in output.
I tried grouping but not sure how to proceed as I am new to DB2.
SQL Fiddle: http://www.sqlfiddle.com/#!2/6d378/1/0
Please note that sql fiddle does not support DB2. I have provided just for providing the table structure.
You can use this query
select U.account_id, U.username from users U
join details D
on U.account_id = D.account_id
group by U.account_id, U.username
having count(distinct super_company) = 1
SQL FIDDLE
You say that you want company in the output, but you do not say what to do when there are multiple companies. Here is one method that outputs one row per user with an arbitrary company:
select u.username, u.accound_id, d.ssn as ssn,
min(d.company) as company, min(d.super_company)
from users u join
details d
on u.accound_id = d.accound_id
group by u.username, u.accound_id
having min(d.super_company) = max(d.super_company);
Actually aggregating multiple company values into a string is harder than it should be in DB2. You can get the individual records for matching users as well. I would do this using window functions:
select username, accound_id, ssn, company, super_company
from (select u.username, d.*,
min(super_company) over (partition by ssn) as minsc,
max(super_company) over (partition by ssn) as maxsc
from users u join
details d
on u.accound_id = d.accound_id
) t
where minsc = maxsc;
This is closer to your specific question, which is about duplicates by ssn, because it does not include username and accound_id when looking for duplicates.
select d.*, u.*
from details d
join users u
on u.accound_id = d.accound_id
join (
select accound_id
from details
group by accound_id
having count(distinct super_company) = 1
) x
on x.accound_id = u.accound_id

SQL Query without nested queries

Let's say we have these tables;
table user:
- id
- username
- email
table user2group:
- userid
- groupid
table group:
- id
- groupname
How do I make one query that returns all users, and the groups they belong to (as an array in the resultset or something..)
select u.id, u.username, u.email, g.groupid, g.groupname
from user u
join user2group ug on u.userid=ug.userid
join group g on g.groupid=ug.groupid
order by u.userid
As you are looping through the result set, each time you see a new userid make a new user object (or whatever) and add the groups to it.
Eric's answer is great, but I would use a LEFT JOIN instead of an INNER to get users that do not belong to any group as well.
SELECT
u.id,
u.username,
u.email,
g.groupid,
g.groupname
FROM
user u
LEFT JOIN user2group ug ON u.userid = ug.userid
LEFT JOIN group g ON g.groupid = ug.groupid
ORDER BY
u.userid
Both of the above are more or less correct (deepends if each user has a group or not). But they will also both give a result set with several entries for each user.
There are ways of concatenating every group member into one comma separated string, I'd suggest you read about it here:
http://www.simple-talk.com/sql/t-sql-programming/concatenating-row-values-in-transact-sql/
Another method I personally like is to use bit values instead of the relational table user2group
table user then gets a int (or bigint) field group, and each group ID is assigned one bit value (ie: 1,2,4,8,16 and so on) The value of the user table's group field is then the sum of the groupID it's assigned to. To query if its got a group you do:
where (group AND groupID = groupID)