I have a user table 'users' that has fields like:
id
first_name
last_name
...
and have another table that determines relationships:
user_id
friend_id
user_accepted
friend_accepted
....
I would like to generate a query that selects all the users but also add another field/column say 'network_status' that depends on the values of user_accepted and fiend_accepted. For example, if user_accepted is true friend_accepted is false I want the 'network_status' field to say 'request sent'. Can I possibly do this in one query? (I would prefer not to user if/else inside the query but if that's the only way so be it)
You will have to take a look at CASE Statement
Something like
SELECT u.id,
u.first_name,
u.last_name,
CASE
WHEN r.user_accepted = 1 AND r.friend_accepted = 0
THEN 'request sent'
ELSE 'Not sure'
END
FROM users u LEFT JOIN
relationships r ON u.id = r.user_id
Related
Suppose I have a table called UserFollows, where I keep Follow relationships ;
UserId
FollowedId
Then I have a general Users table and it is like ;
Id
Username
I use a query like the following when I want to get all followers of a user with ID 100 ;
SELECT*FROM UserFollows WHERE FollowedId = 100;
And suppose that I also want to query the following case ;
I want to search among the followers of a particular user, with a specific Username.
So, It should be like GET ME ALL OF THE USERS THAT HAS THE WORD 'hey' IN THEIR USERNAMES AMONG THOSE FOLLOWING ME
If I had Username in my UserFollows table , I'd easily write it like ;
SELECT*FROM UserFollows WHERE FollowedId = 100 AND Username LIKE '%a';
But I don't keep their Usernames in UserFollows
You need to include the Users table in the query.
SELECT uf.*
FROM UserFollows uf
inner join Users u on u.Id = uf.UserId
WHERE uf.FollowedId = 100
AND u.Username LIKE '%a';
or, more clearly
SELECT uf.*
FROM UserFollows uf
inner join Users follower on follower.Id = uf.UserId
inner join Users followed on followed.Id = uf.FollowedId
WHERE followed.UserName = 'ME'
AND follower.Username LIKE '%a';
Although "followed" may be a keyword, so you would need different aliases or you would need to handle the names appropriately.
When I do a query using the in keyword like so:
select * from users_roles where user_grp in ('SUPPORTER', 'MEMBER', 'VIP');
In this SQL, I'm saying that select those users who are in any one of the user group. So this is a OR logic.
But can I change the OR logic to AND so that I'm and selecting records that are in all or the items in the list?
The table structure is simply using a one-to-many relationship, in which one user can be in multiple groups, so there can have multiple rows of the same user in the users_roles table with different user_grp.
So, how do I write my SQL so that I select users who are in all of the user groups?
You need to apply group by and then select the data that occurs three times after apllying filter
select user_id -- or user_name, whatever
from users
where user_grp in ('SUPPORTER', 'MEMBER', 'VIP')
group by user_id
having count(distinct user_grp) = 3;
I have 3 tables; CASES, USERS and USER_META. For this issue you need to know that the USER_META table has 3 columns; user_id, meta_key and meta_value
Each user is associated with many CASES and each USER is associated with many USER_META
My current query is like this
SELECT CASES.*, USERS.*, USER_META.*
FROM CASES
JOIN USERS ON USERS."user_id" = CASES."user_id"
JOIN USER_META ON USER_META_"user_id" = USERS."user_id"
The problem with this approach is that each USER has A LOT of USER_META so my result set has too many rows. How can I rewrite this query so that I can select only the USER_META where the USER_META."meta_key" is equal to a certain value yet still get the result if they do not have this USER_META."meta_key" set yet
For example:
SELECT CASES.*, USERS.*, USER_META.*
FROM CASES
JOIN USERS ON USERS."user_id" = CASES."user_id"
JOIN USER_META ON USER_META_"user_id" = USERS."user_id"
WHERE USER_META."meta_key" = 'my_key'
This would work great but not all users have a value of "my_key" in the "meta_key" column and we still need to view their CASE. For users that do not have the "meta_key" the result should just return the CASE and USER columns.
How can I rewrite this query so it gets the result for both users with this meta_key and without?
Thanks, I hope this makes sense.
I would use a LEFT JOIN
SELECT CASES.*, USERS.*, USER_META.*
FROM CASES
JOIN USERS ON USERS."user_id" = CASES."user_id"
LEFT JOIN USER_META ON USER_META."user_id" = USERS."user_id" AND USER_META."meta_key" = ?
you need to use OUTER JOIN with the table that may have no results. In Oracle, use (+) near to the field name of the join sentence with this table. This link may help you: http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/queries006.htm
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.
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