PSQL query with join query from a db newbie - sql

I have two database tables. I'll simplify for the sake of this question
USERS
id : int
email: varchar
EVENTS:
user_id: int
event_name: varchar
I'd like to build a query that'll give me an output like:
ID Email Event name
------- --------- ----------------------
1 r#r.com Test event 1
2 d#d.com Test event 2
Obviously the query will select * from EVENTS but will also need to match the user_id in EVENTS via join I assume, to be able to select the e-mail in the USERS table corresponding to the id.
Any ideas how the syntax would look like?

Try this
SELECT
u.id AS ID,
u.email AS Email,
e.event_name AS Event
FROM
users u JOIN events e ON u.id = e.event_id
SQL is best understood with potatoes: http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/

Related

Multi level SQL join

I have 3 different tables names as state, config, and user
state: columns
--------------
taskid
class
state
queue time
running time
config: columns
---------------
class
confname
user: columns
-------------
username
userid
I can join the state and config tables using class column, but in my result set, I want to add the username as well, but there is not matching columns to join. But I can do this via inclusing one more table tasks that has a relationship with the state table.
tasks: columns
--------------
taskid,
userid,
taskname
Using this table, I want to generate the output columns like below.
username - from users table
confname - from config table
state, queue time, running time - from the state table
I tried the following query, but its giving zero results. Can someone help me with the better logic?
select
p.username,
c.confname,
s.state,
s.queue_time/1000000 ||' sec' as queue_time,
s.exec_time/1000000 ||' sec' as execution_time
from
state as s join
config c on s.class=c.class
join ((select distinct(userid)as user from taks q join state s on q.taskid=s.taskid) j
join
user p on j.user=p.username)
Your query has a syntax error. There are more joins than ons.
You are describing something like this:
from state s join
config c
on s.class = c.class left join
task t
on j.taskid = s.taskid left join
user u
on t.user = u.username
Of course, if there are no matching tasks or users, then those columns will be empty.

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

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

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 - re-arrange a table via query

I have a poorly designed table that I inherited.
It looks like:
User Field Value
-------------------
1 name Aaron
1 email aaron#company.com
1 phone 800-555-4545
2 name Mike
2 email mike#group.org
2 phone 777-123-4567
(etc, etc)
I would love to extract this data via a query in the more sensible format:
User Name Email Phone
-------------------------------------------
1 Aaron aaron#company.com 800-555-4545
2 Mike mike#group.org 777-123-4567
I'm a SQL novice, but have tried several queries with variations of Group By,
all without anything even close to success.
Is there a SQL technique to make this easy?
this not a 'badly designed table'; but in fact an Entity Attribute Value (EAV) table. unfortunately, relational databases are poor platforms to implement such tables, and negate most of the nice things of RDBMS. A common case of using the wrong shovel to nail in a screw.
but i think this would work (based on Marcus Adams' answer, which i don't think would work (edit: now it does))
SELECT User1.Value AS name, User2.Value AS email, User3.Value AS phone
FROM Users User1
LEFT JOIN Users User2
ON User2.User = User1.User AND User2.Field='email'
LEFT JOIN Users User3
ON User3.User = User1.User AND User3.Field='phone'
WHERE User1.Field = 'name'
ORDER BY User1.User
Edit: got some niceties from other answers (LEFT Joins, and the field names on the ON clauses), now does anybody know how to put the remaining WHERE a little higher? (but not on the first JOIN's ON, that's too ugly), of course it doesn't matter since the query optimizer uglyfies it back anyway.
At my work we are unfortunate to have a database design like this. But this kind of design works better for us then a traditional database design because of the different records we have to store and gives us the flexibility that we need. The database that we are using stores millions of records.
This would be the fastest way to run the query on a large database using MSSQL. It saves from having to do as many joins which could be very costly.
DECLARE #Results TABLE
(
UserID INT
, Name VARCHAR(50)
, Email VARCHAR(50)
, Phone VARCHAR(50)
)
INSERT INTO #Results
SELECT DISTINCT User FROM UserValues
UPDATE
R
SET
R.Name = UV.Value
FROM
#Results R
INNER JOIN
UserValues UV
ON UV.User = R.UserID
WHERE
UV.Field = 'name'
UPDATE
R
SET
R.Email = UV.Value
FROM
#Results R
INNER JOIN
UserValues UV
ON UV.User = R.UserID
WHERE
UV.Field = 'Email'
UPDATE
R
SET
R.Phone = UV.Value
FROM
#Results R
INNER JOIN
UserValues UV
ON UV.User = R.UserID
WHERE
UV.Field = 'Phone'
SELECT * FROM #Results
You can use a self join:
SELECT User1.User, User1.Value as Name, User2.Value as Email,
User3.Value as Phone
FROM Users User1
JOIN Users User2
ON User2.User = User1.User
JOIN Users User3
ON User3.User = User1.User
WHERE User1.Field = 'name' AND User2.Field = 'email' AND User3.Field = 'phone'
ORDER BY User1.User
I tested this query, and it works.
I believe this will build the result set you're looking for. From there, you can create a view or use the data to populate a new table.
select user, name, email, phone from
(select user, value as name from table where field='name')
natural join
(select user, value as email from table where field='email')
natural join
(select user, value as phone from table where field='phone')
In MySQL you can do something like this:
SELECT
id,
group_concat(CASE WHEN field='name' THEN value ELSE NULL END) AS name,
group_concat(CASE WHEN field='phone' THEN value ELSE NULL END) AS phone,
...
FROM test
GROUP BY id
The aggregate function actually doesn't matter, as long as you have only one field of each type. You could also use min() or max() instead with the same effect.
A variant of Javier's answer, which has my vote.
SELECT
UserName.name, UserEmail.email, UserPhone.phone
FROM
Users AS UserName
INNER JOIN Users AS UserEmail ON UserName.User = UserEmail.User
AND UserName.field = 'name' AND UserEmail.field = 'email'
INNER JOIN Users AS UserPhone ON UserName.User = UserPhone.User
AND UserPhone.field = 'phone'
Use LEFT JOINs if not all attributes are guaranteed to exist. A composite index over (User,Field) would probably be beneficial for this.

Sql Query - stuck with simple left join

I've been stuck with this simple Sql query for last 3 hours and my mind is drawing blank.
I have a User table that captures name user_id etc
Then I have a friends table that captures who is friend of whom and their status
User
user_id
name
Friend
friend_id
user_id
user_friend_id
status (accepeted,pending etc)
What I want to do is - when a logged in user searches for a name say "John" - display a list of all johns on the website and next to each John - do a lookup with a friends table to see if the record exists - ie if the logged in User is a friend of any of the Johns
if it exists show the current status
if it does not exist then show "Add Friend"
So should I first run a query on User table like select user_id from User where name Like 'John%' and then use those Id's and run them against Friends table.
I am not able to get it.
Thanks
You start with all users that match your criterium (I'm not sure about the exact MySQL syntax):
SELECT u.user_id
FROM User u
WHERE u.name LIKE '%John%'
This gives you all target users. Next you want an outer join on the Friend table where you restrict the results to the currently logged in user:
SELECT u.user_id, f.status
FROM user u
LEFT OUTER JOIN Friend f ON f.friend_id = u.user_id
WHERE f.user_id = <currentUserId> AND u.name LIKE '%John%'
What you get is a result set that has the user ids of all users named John and a status flag that is either null or an actual status. If it is null, you have a potential new friend, if not, you have an existing friend.
Something like this might get you started.
COALESCE
SQL Statement
SELECT u.name, COALESCE(f.Status, 'Add Friend')
FROM User u
LEFT OUTER JOIN Friend f ON f.User_ID = u.User_ID
WHERE u.name = 'John'
Following query must solve your problem
select a.user_name,case when a.user_name like 'John%' then b.status else 'Add Friend' end case from users_det a,friend b where a.user_id = b.user_id