Display rooms and count user in each one with simple Sql query - sql

what i want to achieve is this
i got 2 table table 1 = users table 2 = rooms
what i try to do is to get a list of all room but at same time get how many user that are in that specific room.
table rooms contain
id | name | description | limit
table users contain
roomid | username | password
at the end i want to display something like this
room 1 | description | numberofuser / limit
Thanks for any help
currently what i am using to do this is i repeat a query inside a while but if i have 100 rooms then it will make 100 sql query everytime i display the list

I replicated your database and this query works.
SELECT room.id, room.name,
(SELECT COUNT(*) FROM user WHERE room.id=user.roomid)
AS "Occupancy"
FROM room;
Note: My standard is to use singular names for tables (user rather than users) and I called my key to room in the user table"roomid", but you can use yours of course.
Here is the result:
id Name Occupancy
1 PentHouse 4
2 basement 5
3 MeetingRoom 0
You can add limit to the field list. I didn't replicate that.

First get the count using GROUP BY and then perform a JOIN
select r.name,
r.description,
xx.numberofuser_perRoom
from rooms r
join (select roomid, count(*) as numberofuser_perRoom
from users
group by roomid) xx on r.id = xx.roomid;

You didnt specify which DB is that for, nor whether you want to see rows for empty rooms (i assumed yes), so it could look something like this:
SELECT r.name, r.description, COUNT(u.username) * 100. / r.limit
FROM rooms r
LEFT JOIN users u ON u.roomid = r.id
GROUP BY r.name, r.description, r.limit

Related

SQL show multiple values from same columns

There are 2 tables and I must do an inner join.
First table called People
Name, Surname, id, and value
Second table called Work
id (external key of fist table), category, state, roles, date.
Column "Roles" can have multiple values (employee director workers etc).
I must show with inner join the history of roles for each people in one row ( Name Surname roles1, roles 2 roles3)
Example Jack Brown employee director workers
How can I show in one row multiple values contained in one Columns?
If you just need to see the roles but don't really require them to be in separate columns you can use listagg()
select p.id,
p.name,
p.surname,
listagg(w.roles, ',') within group (order by start_date) as all_rows
from people p
join work w on p.id = w.id
group by p.id, p.name, p.surname
This would output something like this:
ID | NAME | SURNAME | ALL_ROLES
---+--------+---------+-------------------------
1 | Jack | Brown | employee,worker,director
You can't actually have each role in a separate column, because in SQL the number of columns in a result is fixed. So you can't have a result that has three columns for the roles of "Jack Brown" and two column for the roles of "Arthur Dent".
You could write PL-SQL function which will select all related records from table Work by given id from table People and iterate it in a cursor to build a string with all of roles or you could generate XML by using of DBMS_XMLGEN.GETXML function if you are using the 10g version of Oracle or higher

SQLite not getting double data

I have rating system which people can rate on ideas. The user can get a summary from the SQLite database of ideas he hasn't voted for yet. My problem is that the database still gets the ideas he already voted for. My Table where the query has to operate looks like this:
ID (pk), ratingScore, userID, ideaID
1 3 1 1
2 4 2 1
3 5 2 2
Ratings score is the score the user has given the idea, userID is the ID of the user who voted and ideaID is the ID of the idea.
How can I get the ideas from user 1 where he hasn't voted for without getting the other ideas, so the result of the query on this table would have been only 'ideaID 2'.
SELECT Ratings.ideaID
FROM Ratings
WHERE (NOT(Ratings.userID)=1)
GROUP BY ideaID;
This is what I tried, but it didn't work, I also tried DISTINCT but that doesn't work either.
Assuming that you have an Ideas table, you could use a correlated subquery like this to find ideas for which no rating for that user exists:
SELECT ID
FROM Ideas
WHERE NOT EXISTS (SELECT 1
FROM Ratings
WHERE userID = 1
AND ideaID = Ideas.ID)
(Reading the ideas from the Ratings table would fail if there is an idea that has not been rated by any user.)
You need to get a list of all ideas and left join it to your table, like this:
SELECT ideas.ideaID
FROM (SELECT DISTINCT ideaID FROM Ratings) ideas LEFT JOIN
Ratings r ON r.ideaID = ideas.ideaID AND r.userID=1
WHERE r.ideaID IS NULL;
The example above will give you a list of unvoted ideas for a single user.

Compare 2 columns in 2 tables with DISTINCT value

I am now creating a reporting service with visual business intelligent.
i try to count how many users have been created under an org_id.
but the report consist of multiple org_id. and i have difficulties on counting how many has been created under that particular org_id.
TBL_USER
USER_ID
0001122
0001234
ABC9999
DEF4545
DEF7676
TBL_ORG
ORG_ID
000
ABC
DEF
EXPECTED OUTPUT
TBL_RESULT
USER_CREATED
000 - 2
ABC - 1
DEF - 2
in my understanding, i need nested SELECT, but so far i have come to nothing.
SELECT COUNT(TBL_USER.USER_ID) AS Expr1
FROM TBL_USER INNER JOIN TBL_ORG
WHERE TBL_USER.USER_ID LIKE 'TBL_ORG.ORG_ID%')
this is totally wrong. but i hope it might give us clue.
It looks like the USER_ID value is the concatenation of your ORG_ID and something to make it unique. I'm assuming this is from a COTS product and nothing a human would have built.
Your desire is to find out how many entries there are by department. In SQL, when you read the word by in a requirement, that implies grouping. The action you want to take is to get a count and the reserved word for that is COUNT. Unless you need something out of the TBL_ORG, I see no need to join to it
SELECT
LEFT(T.USER_ID, 3) AS USER_CREATED
, COUNT(1) AS GroupCount
FROM
TBL_USER AS T
GROUP BY
LEFT(T.USER_ID, 3)
Anything that isn't in an aggregate (COUNT, SUM, AVG, etc) must be in your GROUP BY.
SQLFiddle
I updated the fiddle to also show how you could link to TBL_ORG if you need an element from the row in that table.
-- Need to have the friendly name for an org
-- Now we need to do the join
SELECT
LEFT(T.USER_ID, 3) AS USER_CREATED
, O.SOMETHING_ELSE
, COUNT(1) AS GroupCount
FROM
TBL_USER AS T
-- inner join assumes there will always be a match
INNER JOIN
TBL_ORG AS O
-- Using a function on a column is a performance killer
ON O.ORG_ID = LEFT(T.USER_ID, 3)
GROUP BY
LEFT(T.USER_ID, 3)
, O.SOMETHING_ELSE;

SQL join on one-to-many relation where none of the many match a given value

Say I have two tables
User
-----
id
first_name
last_name
User_Prefs
-----
user_id
pref
Sample data in User_Prefs might be
user_id | pref
2 | SMS_NOTIFICATION
2 | EMAIL_OPT_OUT
2 | PINK_BACKGROUND_ON_FRIDAYS
And some users might have no corresponding rows in User_Prefs.
I need to query for the first name and last name of any user who does NOT have EMAIL_OPT_OUT as one of their (possibly many, possibly none) User_Pref rows.
SELECT DISTINCT u.* from User u
LEFT JOIN User_Prefs up ON (u.id=up.user_id)
WHERE up.pref<>'EMAIL_OPT_OUT'
gets me everyone who has at least one row that isn't "EMAIL_OPT_OUT", which of course is not what I want. I want everyone with no rows that match "EMAIL_OPT_OUT".
Is there a way to have the join type and the join conditions filter out the rows I want to leave out here? Or do I need a sub-query?
I personally think a "where not exists" type of clause might be easier to read, but here's a query with a join that does the same thing.
select distinct u.* from User u
left join User_Prefs up ON u.id = up.user_id and up.pref = 'EMAIL_OPT_OUT'
where up.user_id is null
Why not have your user preferences stored in the user table as boolean fields? This would simplify your queries significantly.
SELECT * FROM User WHERE EMAIL_OPT_OUT = false

SQL question: Show me students who have NOT taken a certain course?

So I have these tables:
STUDENTS:
Student ID - First name - Last name - Email
COURSES:
Catalog ID - Course Name - Description
TERMS:
Term ID - Start Date - End Date
COURSEINSTANCES:
CourseInstance ID - Catalog ID - Term ID
STUDENTCOURSES:
StudentCourse ID - CourseInstance ID - Student ID - Date added to database
This makes it easy to see which students have taken which courses. I'm not sure how to go about finding out which students have NOT taken a particular course.
Doing something like this:
WHERE ((CourseInstances.CatalogLookup)<>504)
will just give me a list of courses taken by students that do not equal catalog number 504 like this:
Tara - 501
Tara - 502
Tara - 505
John - 503
So for example I've taken 504. Therefore I do not want me to show up on this list. The SQL above will just show all of my courses that are not 504, but it will not exclude me from the list.
Any ideas? Is this possible?
I prefer this syntax over outer joins, IMO it's easier to read:
select *
from STUDENTS
where StudentID not in
(
select StudentID
from STUDENTCOURSES s
inner join COURSEINSTANCES c on s.CourseInstanceID = c.CourseInstanceID
where c.CatalogID = 504
)
In the nested query, you select the StudentIDs of all students who HAVE taken course 504.
Then, you select all the students whose StudentIDs are not included in the nested query.
EDIT:
As ChrisJ already said, the c and the s are aliases for the table names.
Without them, the query would look like this:
select *
from STUDENTS
where StudentID not in
(
select StudentID
from STUDENTCOURSES
inner join COURSEINSTANCES on STUDENTCOURSES.CourseInstanceID = COURSEINSTANCES.CourseInstanceID
where CatalogID = 504
)
I always use aliases because:
a) I'm too lazy to type the table names more often than necessary.
b) In my opinion it's easier to read, especially when you join tables with long names.
Try something like this:
SELECT *
FROM Users
WHERE UserID NOT IN
( SELECT UserID
FROM
Users
INNER JOIN
ClassesTaken ON Users.UserID = ClassesTaken.UserID AND ClassesTaken.ClassNumber = 504)
Another way occurred to me the other day:
SELECT *
FROM
Users
LEFT OUTER JOIN ClassesTaken ON Users.UserID = ClassesTaken.UserID AND ClassesTaken.ClassNumber = 504
WHERE ClassesTaken.UserID IS NULL
You should read about outer joins.
SELECT * FROM students
WHERE studentId not in
(SELECT distinct studentID FROM studentCourses WHERE courseInstanceID = 504)
Three main ways in Access
NOT IN (Be careful to exclude any NULLs if there is any possibility of them appearing in the sub query)
OUTER JOIN and filter on NULL (may need DISTINCT added)
NOT EXISTS
Other RDBMSs also have EXCEPT or MINUS
homework? use set operators.
select all students MINUS select any student who has taken this course...