Here is my query:
SELECT *
FROM messages
WHERE status = 1
AND (
poster IN (SELECT thing FROM follows WHERE follower = :uid AND type = 3)
OR
topic_id IN (SELECT thing FROM follows WHERE follower = :uid AND type = 1)
)
ORDER BY post_date DESC LIMIT 0, 20
I want to know which clause the rows come from. From the poster IN (...) part or the topic_id IN (...) part? How can I do that?
A straightforward way:
SELECT *
, CASE WHEN poster IN (SELECT thing FROM follows WHERE follower = :uid AND type = 3) THEN 'poster'
ELSE 'topic_id' END AS from_clause
FROM messages <..>
Another way :
SELECT m.*
, CASE WHEN t1.thing IS NULL THEN 'topic_id' ELSE `poster` END AS from_clause
FROM messages m
LEFT JOIN (SELECT thing FROM follows WHERE follower = :uid AND type = 3) t1 ON m.poster = t1.thing
LEFT JOIN (SELECT thing FROM follows WHERE follower = :uid AND type = 1) t2 ON m.topic_id = t2.thing
WHERE m.status = 1 AND (t1.thing IS NOT NULL OR t2.thing IS NOT NULL)
Related
query taking 1 minute to fetch results
SELECT
`jp`.`id`,
`jp`.`title` AS game_title,
`jp`.`game_type`,
`jp`.`state_abb` AS game_state,
`jp`.`location` AS game_city,
`jp`.`zipcode` AS game_zipcode,
`jp`.`modified_on`,
`jp`.`posted_on`,
`jp`.`game_referal_amount`,
`jp`.`games_referal_amount_type`,
`jp`.`status`,
`jp`.`is_flaged`,
`u`.`id` AS employer_id,
`u`.`email` AS employer_email,
`u`.`name` AS employer_name,
`jf`.`name` AS game_function,
`jp`.`game_freeze_status`,
`jp`.`game_statistics`,
`jp`.`ats_value`,
`jp`.`integration_id`,
`u`.`account_manager_id`,
`jp`.`model_game`,
`jp`.`group_id`,
(CASE
WHEN jp.group_id != '0' THEN gm.group_name
ELSE 'NA'
END) AS group_name,
`jp`.`priority_game`,
(CASE
WHEN jp.country != 'US' THEN jp.country_name
ELSE ''
END) AS game_country,
IFNULL((CASE
WHEN
`jp`.`account_manager_id` IS NULL
OR `jp`.`account_manager_id` = 0
THEN
(SELECT
(CASE
WHEN
account_manager_id IS NULL
OR account_manager_id = 0
THEN
`u`.`account_manager_id`
ELSE account_manager_id
END) AS account_manager_id
FROM
user_user
WHERE
id = (SELECT
user_id
FROM
game_user_assigned
WHERE
game_id = `jp`.`id`
LIMIT 1))
ELSE `jp`.`account_manager_id`
END),
`u`.`account_manager_id`) AS acc,
(SELECT
COUNT(recach_limit_id)
FROM
recach_limit
WHERE
recach_limit = '1'
AND recach_limit_game_id = rpr.recach_limit_game_id) AS somewhatgame,
(SELECT
COUNT(recach_limit_id)
FROM
recach_limit
WHERE
recach_limit = '2'
AND recach_limit_game_id = rpr.recach_limit_game_id) AS verygamecommitted,
(SELECT
COUNT(recach_limit_id)
FROM
recach_limit
WHERE
recach_limit = '3'
AND recach_limit_game_id = rpr.recach_limit_game_id) AS notgame,
(SELECT
COUNT(joa.id) AS applicationcount
FROM
game_refer_to_member jrmm
INNER JOIN
game_refer jrr ON jrr.id = jrmm.rid
INNER JOIN
game_applied joa ON jrmm.id = joa.referred_by
WHERE
jrmm.STATUS = '1'
AND jrr.referby_user_id IN (SELECT
ab_testing_user_id
FROM
ab_testing)
AND joa.game_post_id = rpr.recach_limit_game_id
AND (rpr.recach_limit = 1
OR rpr.recach_limit = 2)) AS gamecount
FROM
(`game_post` AS jp)
JOIN
`user_info` AS u ON `jp`.`user_user_id` = `u`.`id`
JOIN
`game_functional` jf ON `jp`.`game_functional_id` = `jf`.`id`
LEFT JOIN
`group_musesm` gm ON `gm`.`group_id` = `jp`.`group_id`
LEFT JOIN
`recach_limit` rpr ON `jp`.`id` = `rpr`.`recach_limit_game_id`
WHERE
`jp`.`status` != '3'
GROUP BY `jp`.`id`
ORDER BY `posted_on` DESC
LIMIT 10
I would first suggest not nesting select statements because this will cause an n^x performance hit on every xth level and I see at least 3 levels of selects inside this query.
Add index
INDEX(status, posted_on)
Move LIMIT inside
Then, instead of saying
FROM (`game_post` AS jp)
say
FROM ( SELECT id FROM game_post
WHERE status != 3
ORDER BY posted_on DESC
LIMIT 10 ) AS ids
JOIN game_post AS jp USING(id)
(I am assuming that the PK of jp is (id)?)
That should efficiently use the new index to get the 10 ids needed. Then it will reach back into game_post to get the other columns.
LEFT
Also, don't say LEFT unless you need it. It costs something to generate NULLs that you may not be needing.
Is GROUP BY necessary?
If you remove the GROUP BY, does it show dup ids? The above changes may have eliminated the need.
IN(SELECT) may optimize poorly
Change
AND jrr.referby_user_id IN ( SELECT ab_testing_user_id
FROM ab_testing )
to
AND EXISTS ( SELECT * FROM ab_testing
WHERE ab_testing_user_id = jrr.referby_user_id )
(This change may or may not help, depending on the version you are running.)
More
Please provide EXPLAIN SELECT if you need further assistance.
I want to check the validity of a user_id, from a table of users that contains three types of users (type i, c and p).
For users of type c to be valid, the current user.party_id has to be present in the customer_partner table against the supplied $PNR.
For users of type i to be valid, the current user.party_id has top be present in the installer_partner table against the supplied $PNR.
For users of type p to be valid, the current user.party_id has to be the supplied $PNR.
I want the returned row to be the user details if valid, or no rows if invalid. I have tried a couple of ways to do this, but unsuccessfully.
EXAMPLE 1: I am using a CASE in the select then placing a v or e value in the resulting column, then filtering out in the WHERE statement, but this gives me Unknown column 'valid_user' in 'where clause' error.
SELECT
CASE users.party_type
WHEN 'c'
THEN IF(users.party_id IN (SELECT pnrcus.customer_id
FROM customer_partner AS pnrcus
WHERE pnrcus.partner_id = '.$PNR.'),'v','e')
WHEN 'i'
THEN IF(users.party_id IN (SELECT pnrins.installer_id
FROM installer_partner AS pnrins
WHERE pnrins.partner_id = '.$PNR.'),'v','e')
WHEN 'p'
THEN IF(users.party_id = '.$PNR.','v','e')
ELSE 'e'
END AS valid_user,
users.email_user_id,
users.party_id,
users.person_id,
users.first_name,
users.last_name
FROM users AS users
WHERE LCASE(users.email_user_id) = LCASE('.$UID.')
AND users.password = '.$PWD.'
AND valid_user = 'v'
AND users.account_status = 'a'
EXAMPLE 2: I am using OR statements in the WHERE part of the sql. This returns the wrong rows.
SELECT
users.party_type
users.email_user_id,
users.party_id,
users.person_id,
users.first_name,
users.last_name
FROM users AS users
WHERE LCASE(users.email_user_id) = LCASE('.$UID.')
AND users.password = '.$PWD.'
AND users.account_status = 'a'
AND (
parties.party_type = 'c'
AND users.party_id IN (SELECT pnrcus.customer_id
FROM sma_customer_partner AS pnrcus
WHERE pnrcus.partner_id = .$PNR.')
) OR (
parties.party_type = 'i'
AND users.party_id IN (SELECT pnrins.installer_id
FROM sma_installer_partner AS pnrins
WHERE pnrins.partner_id = .$PNR.')
) OR (
parties.party_type = 'p'
AND users.party_id = '.$PNR.'
)
A quick fix to your problem is to add a HAVING clause for the column in the resultset you created:
SELECT
CASE users.party_type
WHEN 'c'
THEN IF(users.party_id IN (SELECT pnrcus.customer_id
FROM customer_partner AS pnrcus
WHERE pnrcus.partner_id = '.$PNR.'),'v','e')
WHEN 'i'
THEN IF(users.party_id IN (SELECT pnrins.installer_id
FROM installer_partner AS pnrins
WHERE pnrins.partner_id = '.$PNR.'),'v','e')
WHEN 'p'
THEN IF(parties.party_id = '.$PNR.','v','e')
ELSE 'e'
END AS valid_user,
users.email_user_id,
users.party_id,
users.person_id,
users.first_name,
users.last_name
FROM users AS users
WHERE LCASE(users.email_user_id) = LCASE('.$UID.')
AND users.password = '.$PWD.'
AND users.account_status = 'a'
HAVING valid_user = 'v'
But, frankly, I'd do this:
SELECT
users.party_type
users.email_user_id,
users.party_id,
users.person_id,
users.first_name,
users.last_name
FROM users AS users
LEFT JOIN customer_partner AS pnrcus
ON pnrcus.partner_id = '.$PNR.'
AND pnrcus.customer_id = users.party_id
AND users.party_type = 'c'
LEFT JOIN installer_partner AS pnrins
ON pnrins.partner_id = '.$PNR.'
AND pnrins.installer_id = users.party_id
AND pnrins.party_type = 'i'
WHERE
LCASE(users.email_user_id) = LCASE('.$UID.')
AND users.password = '.$PWD.'
AND users.account_status = 'a'
AND (
( users.party_type ='p' AND users,party_id = '.$PNR.' )
OR pnrcus.partner_id IS NOT NULL
OR pnrins.partner_id IS NOT NULL
)
GROUP BY users.email_user_id;
Note BTW that this is very slow:
LCASE(users.email_user_id) = LCASE('.$UID.')
You might want to use a collation where 'A'='a' == true (all _ci ones are), or store it lowercase, and provide it lowercase. As it stands it cannot use an index.
When I try this query:
SELECT *
FROM sds_posts
WHERE topic_id = '2439'
AND author = ANY (SELECT mid
FROM sds_actions
WHERE whoami = '710' AND type = 'block')
AND status = '1'
AND deleted = '0'
ORDER BY
id ASC
LIMIT 50
it is working correctly.
But I need this one:
SELECT *
FROM sds_posts
WHERE topic_id = '2439'
AND author <> ANY (SELECT mid
FROM sds_actions
WHERE whoami = '710' AND type = 'block')
AND status = '1'
AND deleted = '0'
ORDER BY
id ASC
LIMIT 50
This time query have to select opposite of first query, but it is just select all author. I tried != and also NOT IN, but result is same.
So why? Why does <> not work as expected?
I would think that changing
and author = any...
to
and NOT author = any...
would work... But if that does not, then I would try doing as a left-join and looking for null. Since the author is the "mid" from the sds_actions, I would write it as...
SELECT
sp.*
FROM
sds_posts sp
LEFT JOIN sds_actions sa
on sp.author = sa.mid
AND sa.whoami = '710'
AND sa.type = 'block'
WHERE
sp.topic_id = '2439'
AND sp.status = '1'
AND sp.deleted = '0'
AND sa.mid IS NULL
ORDER by
sp.id ASC
LIMIT 50
You can try change author = any(...) to author IN (...)
and change author <> any(...) to author NOT IN (...)
I have this:
SELECT users.first_name,
users.last_name,
family_products.costs_obj
FROM users
JOIN family_products
ON users.family_id = family_products.family_id
WHERE users.family_id IN (SELECT family_id
FROM employer_families
WHERE employer_id = 117)
AND family_products.product_id IN (SELECT id
FROM market_products
WHERE type = "medicalplan")
AND users.first_name = 'alexandre'
And i need to be able to update cost_obj to = '' how would i run this select as an update?
Although I have not been able to test this, I think this is what you need:
UPDATE fp
SET fp.costs_obj = ''
FROM
users u
JOIN family_products fp ON u.family_id = fp.family_id
WHERE
u.family_id IN
(
SELECT
family_id
FROM
employer_families
WHERE
employer_id = 117
)
AND
fp.product_id IN
(
SELECT
id
FROM
market_products
WHERE
type = "medicalplan"
)
AND
u.first_name = 'alexandre';
Didn't test this since I don't know the schema, but you can try this:
UPDATE family_products
SET costs_obj = ''
WHERE costs_obj IN(
SELECT
family_products.costs_obj
FROM users
JOIN family_products
ON users.family_id = family_products.family_id
WHERE users.family_id IN (SELECT family_id
FROM employer_families
WHERE employer_id = 117)
AND family_products.product_id IN (SELECT id
FROM market_products
WHERE type = "medicalplan")
AND users.first_name = 'alexandre'
)
Assume tables
team: id, title
team_user: id_team, id_user
I'd like to select teams with just and only specified members. In this example I want team(s) where the only users are those with id 1 and 5, noone else. I came up with this SQL, but it seems to be a little overkill for such simple task.
SELECT team.*, COUNT(`team_user`.id_user) AS cnt
FROM `team`
JOIN `team_user` user0 ON `user0`.id_team = `team`.id AND `user0`.id_user = 1
JOIN `team_user` user1 ON `user1`.id_team = `team`.id AND `user1`.id_user = 5
JOIN `team_user` ON `team_user`.id_team = `team`.id
GROUP BY `team`.id
HAVING cnt = 2
EDIT: Thank you all for your help. If you want to actually try your ideas, you can use example database structure and data found here: http://down.lipe.cz/team_members.sql
How about
SELECT *
FROM team t
JOIN team_user tu ON (tu.id_team = t.id)
GROUP BY t.id
HAVING (SUM(tu.id_user IN (1,5)) = 2) AND (SUM(tu.id_user NOT IN (1,5)) = 0)
I'm assuming a unique index on team_user(id_team, id_user).
You can use
SELECT
DISTINCT id,
COUNT(tu.id_user) as cnt
FROM
team t
JOIN team_user tu ON ( tu.id_team = t.id )
GROUP BY
t.id
HAVING
count(tu.user_id) = count( CASE WHEN tu.user_id = 1 or tu.user_id = 5 THEN 1 ELSE 0 END )
AND cnt = 2
Not sure why you'd need the cnt = 2 condition, the query would get only those teams where all of users having the ID of either 1 or 5
Try This
SELECT team.*, COUNT(`team_user`.id_user) AS cnt FROM `team`
JOIN `team_user` ON `team_user`.id_team = `team`.id
where `team_user`.id_user IN (1,5)
GROUP BY `team`.id
HAVING cnt = 2