MySQL: Putting condition in SELECT query based on column value - mysql

I have two tables user_profiles and user_friends.
user_profiles has columns id, user_privacy and few other columns (like username, age etc).
user_friends has columns user_id and friends_id. One user_id can have multiple friend_ids
This query simply returns profile of user having id, say, 1997:
select * from user_profiles
where prfls.id=1997;
And this query returns profile of user having id 1997 only when it has got friend having id, say, 2001:
select * from user_profiles prfls
inner join user_friends frnds on (prfls.id=frnds.user_id)
where prfls.id=1997 and frnds.friends_id=2001;
However, I want to write a single query that will check if column user_privacy (in user_profiles) for user 1997 is false then the query shouldn't check for friends_id in user_friends. It should simply return profile of user 1997. But if the user_privacy is true then only it should check for it.
How can this query be written? (Preferably using joins and without using sub-queries)

Use left join for it:
select distinct t1.* from user_profiles t1
left join user_friends t2 on(t1.id = t2.user_id)
where t1.id = 1997 and
(user_privacy='false' or t2.friends_id = 2001)

Try this;)
select t1.*
from user_profiles t1
where t1.id = 1997
and (
t1.user_privacy = 'false'
or exists (select 1 from user_friends t2 where t1.id = t2.user_id and t2.friends_id = 2001)
)
Without subquery, you can try this;)
select distinct t1.*
from user_profiles t1
inner join user_friends t2
on t1.id = 1997 and (t1.user_privacy = 'false' or (t1.id = t2.user_id and t2.friends_id = 2001))

SELECT *
FROM user_profiles P
LEFT JOIN user_friends F ON F.user_id = P.id
AND P.user_privacy = true
AND F.friends_id = 2001
WHERE P.id = 1997
Use LEFT JOIN so even if user_privacy is false, the query will still return the user_profiles
Add condition in the ON clause of LEFT JOIN indicating that it will return the user_friends if user_privacy is true.
Move the filtering of F.friends_id in the ON clause of the LEFT JOIN. (Thanks to #Msf vtp for verifying, cheers!)

Related

Calculating SUM() results from subqueries into a total

My brain is starting to hurt with this query and I would appreciate some guidance. What I am trying to get as the result of this query are three values: attendanceScore, lootScore, and totalScore (attendanceScore - lootScore).
Attendance is tracked across three tables: attendance, attendancelog, and attendancevalues.
attendance records an individual's attendance status attached to an attendancelog record. There are types of attendance such as "attended", "missed", and "called out".
attendancelog is the parent record which records the event type, title and date as well as who logged the attendance and when.
attendancevalues is a config table that matches the attendance type from attendance and the event type from attendancelog and returns a configurable value FLOAT.
Loot is tracked across two tables: loot and loottypes.
loot logs each individual item, who received it and when and what type of loot it was (Primary, Secondary, Free-for-all).
loottypes is a config table that takes the type from loot and returns a configurable cost FLOAT.
After some work I have come up with a working query to get attendanceScore and lootScore:
SELECT
(SELECT SUM(t3.`value`)
FROM `attendance` t1
INNER JOIN `attendancelog` t2
ON t2.`id` = t1.`attendancelog_id`
INNER JOIN `attendancevalues` t3
ON t3.`eventtype_id` = t2.`type` AND t3.`attendancetype_id` = t1.`type`
WHERE t1.`user_id` = 3) as attendanceScore,
(SELECT SUM(t2.`cost`)
FROM `loot` t1
INNER JOIN `loottypes` t2
ON t2.`id` = t1.`type`
WHERE t1.`user_id` = 3) as lootScore
I know this doesn't work, but I tried to add (attendanceScore - lootScore) to the query but it says those fields are not available. That is ultimately what I need to complete the query.
I can get the result I want by copying each of the subqueries directly into (attendanceScore - lootScore) but it is just absolutely hideous and I'm sure unnecessary:
SELECT
(SELECT SUM(t3.`value`)
FROM `attendance` t1
INNER JOIN `attendancelog` t2
ON t2.`id` = t1.`attendancelog_id`
INNER JOIN `attendancevalues` t3
ON t3.`eventtype_id` = t2.`type` AND t3.`attendancetype_id` = t1.`type`
WHERE t1.`user_id` = 3) as attendanceScore,
(SELECT SUM(t2.`cost`)
FROM `loot` t1
INNER JOIN `loottypes` t2
ON t2.`id` = t1.`type`
WHERE t1.`user_id` = 3) as lootScore,
(
(SELECT SUM(t3.`value`)
FROM `attendance` t1
INNER JOIN `attendancelog` t2
ON t2.`id` = t1.`attendancelog_id`
INNER JOIN `attendancevalues` t3
ON t3.`eventtype_id` = t2.`type` AND t3.`attendancetype_id` = t1.`type`
WHERE t1.`user_id` = 3) - (SELECT SUM(t2.`cost`)
FROM `loot` t1
INNER JOIN `loottypes` t2
ON t2.`id` = t1.`type`
WHERE t1.`user_id` = 3)
) as totalScore
Could someone help me understand what methods to use for cleaning this up into something more streamlined and efficient?
You may use an inline view
SELECT attendanceScore,
lootScore,
attendanceScore - lootScore as totalScore
FROM
(
SELECT
(
SELECT SUM(t3.`value`)
FROM `attendance` t1
INNER JOIN `attendancelog` t2
ON t2.`id` = t1.`attendancelog_id`
INNER JOIN `attendancevalues` t3
ON t3.`eventtype_id` = t2.`type` AND t3.`attendancetype_id` = t1.`type`
WHERE t1.`user_id` = 3
) as attendanceScore,
(
SELECT SUM(t2.`cost`)
FROM `loot` t1
INNER JOIN `loottypes` t2 ON t2.`id` = t1.`type`
WHERE t1.`user_id` = 3) as lootScore
) t

MySQL - Joining table on itself based on criteria from other table

Here’s the problem I am trying to solve:
Table1 has Product ID’s, dates, and prices for those dates, Table2 has Product attributes.
I want to be able to compare prices for a client for different products on the same date based on a set of attributes. I’m easily able to get a list of products/dates/prices for a ‘simple’ product, as well as an ‘advanced’ product (see below).
I want to be able to join these two tables such that the output looks like:
[CLIENT] [PRODUCT] [DATE] [SIM_PROD] [SIM_PRICE] [ADV_PROD] [ADV_PRICE]
Here is as far as I've made it
SELECT b.NAME AS ‘CLIENT’, a.NAME AS ‘SIMPLE_PRODUCT’, t1.DATE AS ‘DATE’, t1.PIVOT_PRICE AS ‘SIMPLE_PRICE’
FROM TABLE1 t1
LEFT JOIN PRODUCT a
ON t1.PRODUCT_ID = a_PRODUCT_ID
LEFT JOIN CLIENTS b
ON a.PARTNER_ID = b.PARTNER_ID
WHERE a.CRITERIA = TRUE;
SELECT b.NAME AS ‘CLIENT’, a.NAME AS ‘ADV_PRODUCT’, t2.DATE AS ‘DATE’, t2.PIVOT_PRICE AS ‘ADV_PRICE’
FROM TABLE1 t2
LEFT JOIN PRODUCT a
ON t2.PRODUCT_ID = a_PRODUCT_ID
LEFT JOIN CLIENTS b
ON a.PARTNER_ID = b.PARTNER_ID
WHERE a.CRITERIA = FALSE;
I've been able to build similar tables where I pull in price from TABLE1 labeling it as t1 then pull in price again from TABLE1 and labeling it as t2, but only when using criteria in TABLE1, not criteria in a table that needs to be joined.
Is it possible to 'set' a table (EG simple) then 'set' a second one (EG advanced) and then join them on PARTNER_ID and DATE?
You can join the two subqueries:
SELECT t1.client, t1.date, t1.simple_product, t1.simple_price, t2.adv_product, t2.adv_price
FROM (
SELECT b.NAME AS CLIENT, a.NAME AS SIMPLE_PRODUCT, t1.DATE, t1.PIVOT_PRICE AS SIMPLE_PRICE
FROM TABLE1 t1
LEFT JOIN PRODUCT a
ON t1.PRODUCT_ID = a_PRODUCT_ID
LEFT JOIN CLIENTS b
ON a.PARTNER_ID = b.PARTNER_ID
WHERE a.CRITERIA = TRUE
) AS t1
JOIN (
SELECT b.NAME AS CLIENT, a.NAME AS SIMPLE_PRODUCT, t1.DATE, t1.PIVOT_PRICE AS SIMPLE_PRICE
FROM TABLE1 t1
LEFT JOIN PRODUCT a
ON t1.PRODUCT_ID = a_PRODUCT_ID
LEFT JOIN CLIENTS b
ON a.PARTNER_ID = b.PARTNER_ID
WHERE a.CRITERIA = FALSE
) AS t2
ON t1.client = t2.client AND t1.date = t2.date
You'll probably need to select additional criteria and add them to the ON condition. Otherwise this will produce a full cross product between all the products that have the same client and date.
Your desired output has an additional PRODUCT column, but I couldn't see where that comes from.

'IF' in 'FROM' statement - choose table value based on column value

SELECT CI FROM users WHERE something;
IF users.CI='pc' THEN
SELECT name FROM table1 WHERE something;
ELSE IF users.CI='ph' THEN
SELECT name FROM table2 WHERE something;
END IF
I know that doesn't work, but is an example to understand.
It's possible all of this in one query ?
SET #var = (SELECT CI FROM users WHERE something);
SELECT
CASE #var
WHEN 'pc' THEN
(SELECT name FROM table1 WHERE something)
WHEN 'ph' THEN
(SELECT name FROM table2 WHERE something)
END;
You cannot use IF ... THEN in a SQL query.
The solution is to left outer join both tables, letting the optimizer choose which table will be used by specifying so in the ON clauses.
You didn't explain what "something" was, so in this example, I am going to assume that "users" has an "id" column and that table1 and table2 have a "user_id" column, and that you are interested in the user with id = 1.
SELECT COALESCE(t1.name,t2.name) AS name
FROM users u
LEFT JOIN table1 t1 ON u.CI = 'pc' AND t1.user_id = u.id
LEFT JOIN table2 t2 ON u.CI = 'ph' AND t2.user_id = u.id
WHERE u.id = 1;

Comparing two tables where one column matches and the other doesn't

Hi I am trying to compare two tables based on two columns. I to see where the usernames match between the tables and the email addresses don't match.
Here is what I tried:
select * from ecy t1, users t2 where t1.username = t2.username and t1.email <> t2.email
When I run this I get all the users in the ecy table even if their emails are equal.
Thanks.
I wouldn't do the Cartesian Product of the two tables and try to filter it with the old Ansi way.
SELECT u.username, u.email
FROM users u
JOIN ecy e on e.email <> u.email AND u.username = e.username
you could also try doing it with a subquery select that is joined
SELECT username, email
FROM users u
JOIN( SELECT username, email FROM ecy) t on t.username = u.username and t.email <> u.email
DEMO
you want to use the JOIN syntax to join tables together and not do a Cartesian Product. the JOIN syntax will also allow you to filter out data as it joins
you can try this, i didn't use <> before in mysql.
select * from ecy t1, users t2 where t1.username = t2.username and not t1.email = t2.email

mysql inner join on multiple select statements

Trying to do an inner join on two composite tables, having trouble with the syntax. Here's what I have:
SELECT
count(*)
FROM
(
SELECT DISTINCT seller FROM Items, Users WHERE Items.seller = Users.userID t1
INNER JOIN
(
SELECT DISTINCT UserID FROM Bids, Users WHERE Bids.UserID = Users.userID
)
t2 ON t1.userID = t2.userID
)
I'm guessing it has something to do with the parantheses/lack of as/or whatever. I guess what I'm really asking here is how to give my subqueries aliases, but not using as in the FROM part. Is it valid just to have t1 after User.userID and identify that whole table as t1?
I think this is what you want?
SELECT count(*)
FROM Users
INNER JOIN Items ON Users.userID = Items.seller
INNER JOIN Bids ON Users.UserID = Bids.UserID
You want to name the output table which you get from query
SELECT DISTINCT seller FROM Items, Users WHERE Items.seller = Users.userID
as t1
simple way is use
`select * from (SELECT DISTINCT seller FROM Items, Users WHERE Items.seller = Users.userID)t1`