MySQL multiple tables conditional filter - mysql

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.

Related

SELECT Statement should return 0 when condition is not met

How can I make following MYSQL statment return 0 in case that the condition is not met.
(SELECT Sum(B.trblksize) AS RxData
FROM referencecoexistence_ber_lte B,
(SELECT C.*
FROM referencecoexistence C
WHERE `sw_ver` = '0.4'
AND `lte_n_frames` = '50'
AND `lte_rb` = '6'
AND `lte_mcs` = '11'
AND `lte_p_mw` = '6.000000e-03'
AND `lte_vmsf_type` = 'BS'
AND `lte_vmsf_subframes` = '8 9'
AND `wlan_mcs` = '5'
AND `wlan_p_mw` = '100'
AND `channel` = 'A330'
AND `lte_freq_hz` = '2403000000'
AND `wlan_freq_hz` = '2412000000'
AND `wlan_ieee` = '802.11n') AS TableX
WHERE TableX.id = B.id
AND B.ber = '0'
GROUP BY lte_dist_m)
The result is: Empty set (0.280 sec)
If the condition includes B.ber = '0' the expected output is:
A result with b.ber = 0 looks like:
RxData
416342016
433004544
...
In my case it would be sufficient if it simply returns one entry:
RxData
0
This statement is embedded in a larger statement that calculates some throughput.
Is it possible without executing the statement twice?
Here we'll change this to a LEFT OUTER JOIN. We will move the B.ber = '0' condition into the FROM clause, because with an outer join, this will give us different results than if the condition is in the WHERE clause.
SELECT Sum(B.trblksize) AS RxData
FROM (SELECT C.*
FROM referencecoexistence C
WHERE `sw_ver` = '0.4'
AND `lte_n_frames` = '50'
AND `lte_rb` = '6'
AND `lte_mcs` = '11'
AND `lte_p_mw` = '6.000000e-03'
AND `lte_vmsf_type` = 'BS'
AND `lte_vmsf_subframes` = '8 9'
AND `wlan_mcs` = '5'
AND `wlan_p_mw` = '100'
AND `channel` = 'A330'
AND `lte_freq_hz` = '2403000000'
AND `wlan_freq_hz` = '2412000000'
AND `wlan_ieee` = '802.11n') AS TableX
LEFT OUTER JOIN referencecoexistence_ber_lte B
ON TableX.id = B.id
AND B.ber = '0'
GROUP BY lte_dist_m
Now when B.ber is zero, it will act like an inner join. However, when B.ber is not zero, then the inner join result will be missing from the join, but the outer join will include the result with all the columns of the B table, but NULL for all the columns of the TableX table. So those records will have B.trblksize as NULL, and their sum will be NULL.
I solved the problem by simply using following approach
(SELECT SUM(IF(T_.BER =0,T_.TrBlkSize,0)) as RxData, Lte_Dist_m FROM
(ReferenceCoexistence WHERE <CONDITION LIST>) as X,
ReferenceCoexistence_BER_Lte as T_
WHERE X.ID = T_.ID GROUP BY Lte_Dist_m)

Select with case when + join, MYSQL

Guys are you able to help me in this below case?
I'm wanna to select and change the results:
My code looks as follow:
$USER_STORY = $this->lang->line('application_status_change_user_story');
$TO_DO = $this->lang->line('application_status_change_to_do');
$IN_PROGRESS = $this->lang->line('application_status_change_in_progress');
$DONE = $this->lang->line('application_status_change_done');
$UNDONE = $this->lang->line('application_status_change_undone');
SELECT sum(project_has_tasks.estimated_hours) as val, project_has_tasks.name,
project_has_tasks.start_date,
project_has_tasks.due_date,
project_has_tasks.progress,
TIME_FORMAT(SEC_TO_TIME(sum(project_has_tasks.time_spent)),'%k.%i')
as total_time, users.id, users.firstname, users.lastname,(case
when 'user_story' then '$USER_STORY'
when 'to_do' then '$TO_DO'
when 'in_progress' then '$IN_PROGRESS'
when 'done' then '$DONE'
when 'undone' then '$UNDONE'
else 'NOTHING'
end) as status
FROM project_has_tasks
RIGHT JOIN users ON project_has_tasks.user_id
= users.id WHERE project_has_tasks.project_id ='99'
GROUP BY project_has_tasks.id ASC
What to modify to get a proper results? Now I'm getting NOTHING in status column, but no errors.
I think your case statement is wrong, There no condition is checking so only it return the last else statement
SELECT sum(project_has_tasks.estimated_hours) as val, project_has_tasks.name,
project_has_tasks.start_date,
project_has_tasks.due_date,
project_has_tasks.progress,
TIME_FORMAT(SEC_TO_TIME(sum(project_has_tasks.time_spent)),'%k.%i')
as total_time, users.id, users.firstname, users.lastname,(case
when project_has_tasks.status = 'user_story' then '$USER_STORY'
when project_has_tasks.status = 'to_do' then '$TO_DO'
when project_has_tasks.status = 'in_progress' then '$IN_PROGRESS'
when project_has_tasks.status = 'done' then '$DONE'
when project_has_tasks.status = 'undone' then '$UNDONE'
else 'NOTHING'
end) as status
FROM project_has_tasks
RIGHT JOIN users ON project_has_tasks.user_id
= users.id WHERE project_has_tasks.project_id ='99'
GROUP BY project_has_tasks.id ASC

Which table does the row come from?

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)

Need to create an update from a Join with nested selects

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'
)

MySQL error: Operand should contain 1 column(s)

I have this MySQL Query (working)
First query:
SELECT id
FROM users
WHERE publisher_set = '1'
AND publisher_status = '1'
AND publisher_content != ''
AND publisher_amount != '0'
AND publisher_now < publisher_max
AND EXISTS (
SELECT *
FROM user_counter
WHERE users.id = user_counter.publisher_id
)
The MySQL query above is to find the user id from two table
Now I want to compared again using this second MySQL query (working)
Second query:
SELECT users.id, publisher_amount, publisher_now, publisher_max, counter
FROM users
INNER JOIN user_counter ON users.id = user_counter.publisher_id
WHERE no = 08123456789
AND counter < publisher_amount
But when I join all the query like this:
SELECT id
FROM users
WHERE publisher_set = '1'
AND publisher_status = '1'
AND publisher_content != ''
AND publisher_amount != '0'
AND publisher_now < publisher_max
AND EXISTS (
SELECT *
FROM user_counter
WHERE users.id = user_counter.publisher_id
)
AND (
SELECT users.id, publisher_amount, publisher_now, publisher_max, counter
FROM users
INNER JOIN user_counter ON users.id = user_counter.publisher_id
WHERE no =08123456789
AND counter < publisher_amount
)
I get this error:
Operand should contain 1 column(s)
Then, I try using 1 column, but the result is not what I wanted.
My question is How to join first and second query ? and produce no error.
I have tried google it and after many "try-and-error" this is the far I can get to make the query work.
I think you just miss an EXISTS on your second subquery. Anyway, if I understand your query correctly, I think you could write your query as this:
SELECT
u.id
FROM
users u inner join user_counter uc
on u.id=uc.publisher_id
and no=08123456789
and counter < publisher_amount
WHERE
u.publisher_set = '1'
AND u.publisher_status = '1'
AND u.publisher_content != ''
AND u.publisher_amount != '0'
AND u.publisher_now < publisher_max
You could change the first EXISTS clause to:
and users.id in (select user_counter.publisher_id from user_counter)
and use EXISTS on the final query.
You could also do this:
AND EXISTS (
SELECT user_counter.publisher_id
FROM user_counter
WHERE users.id = user_counter.publisher_id
PS: SQLFIDDLE doesn't work in my end for some reason. Else would have been happy to give you a demonstration ;)
SELECT id
FROM users
WHERE publisher_set = '1'
AND publisher_status = '1'
AND publisher_content != ''
AND publisher_amount != '0'
AND publisher_now < publisher_max
AND EXISTS (
select 1 from user_counter where users.id = user_counter.publisher_id
and no =08123456789
AND counter < publisher_amount
)
Assuming no and counter are on table user_counter. A bit hard to tell without a schema.