Using Exists when Union All is present in the Sub Query - mysql

I wanted to modify the query I wrote using the IN operator to using the Exists operator. However, the problem is that I have union all in my subquery. As I do not have much experience with using exists in such scenario I was looking for some help.
This was the initial query:
select APP_NUM,SBM_INDV_ID
from T1004_APP_INDV indv
where INDV.APP_NUM = 'T23952717'
and INDV.SBM_INDV_ID in
(select EMPL.INDV_ID
from DC_EMPLOYMENT EMPL
where EMPL.LOST_EMPLOYMENT_SW = 'N'
and EMPL.TERMINATION_DT is null
and (EMPL.EFF_END_DT is null
or EMPL.EFF_END_DT >= TRUNC(SYSDATE))
union all
select UNEARN.INDV_ID
from DC_UNEARNED_INCOME UNEARN
where UNEARN.EFF_END_DT is null
or UNEARN.EFF_END_DT >= TRUNC(SYSDATE)
union all
select RBINC.INDV_ID
from DC_ROOM_BOARD_INCOME RBINC
where RBINC.EFF_END_DT is null
or RBINC.EFF_END_DT >= TRUNC(SYSDATE)
union all
select SELFEMP.INDV_ID
from DC_SELF_EMP_INCOME SELFEMP
where SELFEMP.EFF_END_DT is null
or SELFEMP.EFF_END_DT >= TRUNC(SYSDATE)
);
I tried changing the initial query as follows:
select APP_NUM,SBM_INDV_ID
from T1004_APP_INDV APPINDV
where APPINDV.APP_NUM = 'T23952717'
and exists
(select EMPL.INDV_ID
from DC_EMPLOYMENT EMPL
where APPINDV.SBM_INDV_ID = EMPL.INDV_ID
and EMPL.LOST_EMPLOYMENT_SW = 'N'
and EMPL.TERMINATION_DT is null
and (EMPL.EFF_END_DT is null
or EMPL.EFF_END_DT >= TRUNC(SYSDATE))
union all
select UNEARN.INDV_ID
from DC_UNEARNED_INCOME UNEARN
where APPINDV.SBM_INDV_ID = UNEARN.INDV_ID
and UNEARN.EFF_END_DT is null
or UNEARN.EFF_END_DT >= TRUNC(SYSDATE)
union all
select RBINC.INDV_ID
from DC_ROOM_BOARD_INCOME RBINC
where APPINDV.SBM_INDV_ID = RBINC.INDV_ID
and RBINC.EFF_END_DT is null
or RBINC.EFF_END_DT >= TRUNC(SYSDATE)
union all
select SELFEMP.INDV_ID
from DC_SELF_EMP_INCOME SELFEMP
where APPINDV.SBM_INDV_ID = SELFEMP.INDV_ID
and SELFEMP.EFF_END_DT is null
or SELFEMP.EFF_END_DT >= TRUNC(SYSDATE));
Is the second query correct? Does it produce the same result as the previous query?
Thanks

I think splitting this into separate queries makes it simpler for the optimizer:
where APPINDV.APP_NUM = 'T23952717' and
( exists (select 1
from DC_EMPLOYMENT EMPL
where APPINDV.SBM_INDV_ID = EMPL.INDV_ID and
EMPL.LOST_EMPLOYMENT_SW = 'N' and
EMPL.TERMINATION_DT is null and
(EMPL.EFF_END_DT is null or EMPL.EFF_END_DT >= TRUNC(SYSDATE)
) or
exists (select 1
from DC_UNEARNED_INCOME UNEARN
where APPINDV.SBM_INDV_ID = UNEARN.INDV_ID and
( UNEARN.EFF_END_DT is null and or UNEARN.EFF_END_DT >= TRUNC(SYSDATE) )
) or
. . .
)

Related

Cannot handle right syntax for Mysql multiple else if query

Here is the query:
SELECT t1.id,
(
IF t1.sms_phone IS NOT NULL THEN t1.sms_phone
ELSE IF t1.insuringPhone IS NOT NULL THEN t1.insuringPhone
ELSE IF t1.person_id IS NOT NULL THEN (SELECT person_contact.value FROM person_contact where person_contact.person_id = t1.person_id AND person_contact.contact_id = 2 ORDER BY person_contact.last_change DESC LIMIT 1) END IF) as phone
FROM test_table as t1
WHERE id = 187842
Also tried with CASE without success:
SELECT t1.id,
(
CASE
WHEN t1.sms_phone IS NOT NULL THEN t1.sms_phone
WHEN t1.insuringPhone IS NOT NULL THEN t1.insuringPhone
WHEN t1.person_id IS NOT NULL THEN (SELECT person_contact.value FROM person_contact where person_contact.person_id = t1.person_id AND person_contact.contact_id = 2 ORDER BY person_contact.last_change DESC LIMIT 1)
) as phone
FROM test_table as t1
WHERE id = 187842
Use COALESCE which returns the first non-null argument.
SELECT t1.id, COALESCE(t1.sms_phone, t1.insuringPhone, ...)
For person_id an other solution seems better: maybe if a limited COALESCE returns NULL,
query further.

Count Total from Multiple Tables

I have list table that basically contains same field on each part.
- p_ticket1_m_site_data | - p_ticket1_ticket | - p_ticket1_last_row
- p_ticket2_m_site_data | - p_ticket2_ticket | - p_ticket2_last_row
- p_ticket3_m_site_data | - p_ticket3_ticket | - p_ticket3_last_row
I can do a count on each table individually:
SELECT COUNT( * ) AS tot_sites, IFNULL( COUNT(
CASE WHEN p_ticket1_m_site_data.m_date_target = DATE( NOW( ) )
THEN 1
ELSE NULL
END ),0) AS todays_target, IFNULL( COUNT(
CASE WHEN (
p_ticket1_m_site_data.m_date_target = DATE( NOW( ) )
AND p_ticket1_ticket.t_status =9 )
THEN 1
ELSE NULL
END ),0
) AS todays_achieve, IFNULL( COUNT(
CASE WHEN p_ticket1_ticket.t_status =9
THEN 1
ELSE NULL
END ),0 ) AS tot_in
FROM p_ticket1_m_site_data
LEFT JOIN p_ticket1_last_row ON p_ticket1_last_row.t_m_id = p_ticket1_m_site_data.m_id
AND p_ticket1_last_row.t_req_type = '04_int_finish_ack'
LEFT JOIN p_ticket1_ticket ON p_ticket1_ticket.t_id = p_ticket1_last_row.t_id
WHERE p_ticket1_m_site_data.m_status =1
What should i do if i want to count all total sites from ticket1, ticket2, ticket3 ?
Please help me guys, thanks . . .
Example use UNION ALL:
I just using UNION ALL in my code above for ticket1 and ticket2, but its not what i want.
My expectation output is count all the ticket tables, so the view is tot_sites (from all ticket), todays_target(from all ticket), todays_achieve(from all ticket), and tot_in(from all ticket)
If you are sure that your tables have the same columns, you should use UNION ALL with CTE
WITH CTE AS (
SELECT *
FROM p_ticket1_m_site_data
UNION ALL
SELECT *
FROM p_ticket2_m_site_data
UNION ALL
...
)
SELECT COUNT(*), ...
FROM CTE
WHERE CTE.m_status = 1
CTE
UNION ALL
You can union the three sets of tables in a sub query and then do your counts in the main query , something like this in principal
SELECT COUNT( * ) AS tot_sites, IFNULL( COUNT(
CASE WHEN m_date_target = DATE( NOW( ) )
THEN 1
ELSE NULL
END ),0) AS todays_target, IFNULL( COUNT(
CASE WHEN (m_date_target = DATE( NOW( ) )
AND t_status =9 )
THEN 1
ELSE NULL
END ),0
) AS todays_achieve, IFNULL( COUNT(
CASE WHEN t_status =9
THEN 1
ELSE NULL
END ),0 ) AS tot_in
from
(
select *
FROM p_ticket1_m_site_data
LEFT JOIN p_ticket1_last_row ON p_ticket1_last_row.t_m_id = p_ticket1_m_site_data.m_id
AND p_ticket1_last_row.t_req_type = '04_int_finish_ack'
LEFT JOIN p_ticket1_ticket ON p_ticket1_ticket.t_id = p_ticket1_last_row.t_id
WHERE p_ticket1_m_site_data.m_status =1
union all
select *
frOM p_ticket2_m_site_data
LEFT JOIN p_ticket2_last_row ON p_ticket2_last_row.t_m_id = p_ticket2_m_site_data.m_id
AND p_ticket2_last_row.t_req_type = '04_int_finish_ack'
LEFT JOIN p_ticket2_ticket ON p_ticket2_ticket.t_id = p_ticket2_last_row.t_id
WHERE p_ticket2_m_site_data.m_status =1
union all
select *
fROM p_ticket3_m_site_data
LEFT JOIN p_ticket3_last_row ON p_ticket3_last_row.t_m_id = p_ticket3_m_site_data.m_id
AND p_ticket3_last_row.t_req_type = '04_int_finish_ack'
LEFT JOIN p_ticket3_ticket ON p_ticket3_ticket.t_id = p_ticket3_last_row.t_id
WHERE p_ticket3_m_site_data.m_status =1
) j;
Which could be tidied up. If this doesn't work for you please add sample data and expected output for your 3 tables as text to the question and I will review.

Two select statements

SELECT COUNT( DISTINCT `student_id` )
FROM a
WHERE `marks` >=90
The above gives me count of student with marks greater than 90,
COUNT( DISTINCT `student_id` )
4
Now I want two answers, one with marks > 90 and another >80
Something like this
COUNT( DISTINCT `student_id` ) |COUNT( DISTINCT `student_id` )
4 5
This is what I have tried after google search
select
count_1 =( SELECT COUNT( DISTINCT `student_id` )
FROM a
WHERE `marks` >=90),
count_2 =( SELECT COUNT( DISTINCT `student_id` )
FROM a
WHERE `marks` >=80)
I think the simpliest answer would be by using implicit boolean condition since MySQL supports it,
SELECT SUM(marks >= 90) Count_1,
SUM(marks >= 80) Count_1
FROM a
WHERE marks >= 80
The WHERE clause makes the searching more faster since it will filter the records first than running through all records.
You can use a CASE expression with an aggregate function:
SELECT
sum(case when `marks` >= 90 then 1 else 0 end) count_1,
sum(case when `marks` >= 80 then 1 else 0 end) count_2
FROM a
Then if you have more counts to get you will add more case expressions.
Or you can use:
SELECT
count(distinct case when `marks` >= 90 then `student_id` end) count_1,
count(distinct case when `marks` >= 80 then `student_id` end) count_2
FROM a

MySQL - Want to Minus two SUM() values from two SELECT statements

I want to be able to grab the two values that I have generated in SUM() from two SELECT queries and minus these values in order to get the result (OutstandingFunds).
These are my two SELECT queries:
Statement (1):
SELECT SUM(Cf.Amount) AS ClearedFunds
FROM (
SELECT Amount FROM PAYMENT1 WHERE `Status` = "Cleared"
UNION ALL
SELECT Amount FROM PAYMENT2 WHERE `Status` = "Cleared"
UNION ALL
SELECT Amount FROM PAYMENT3 WHERE `Status` = "Cleared") AS Cf;
Statement (2):
SELECT SUM(Price) AS TotalSales
FROM PROPERTY
WHERE Status = “Sold”;
Thank you for your time
If you don't need to show the separate subtotal for total sales and cleared funds, you can do it like this:
SELECT SUM(Total.`Price`) AS ClearedFunds
FROM (
SELECT `Price` FROM PROPERTY WHERE `Status` = 'Sold'
UNION ALL
SELECT (`Amount` * -1) AS `Price` FROM PAYMENT1 WHERE `Status` = 'Cleared'
UNION ALL
SELECT (`Amount` * -1) AS `Price` FROM PAYMENT2 WHERE `Status` = 'Cleared'
UNION ALL
SELECT (`Amount` * -1) AS `Price` FROM PAYMENT3 WHERE `Status` = 'Cleared'
) AS Total;
I am assuming you are wanting to subtract cleared funds from total sales here.
You were almost there... here's the working SQL:
SELECT (SELECT SUM(Cf.Amount) AS ClearedFunds
FROM (
SELECT Amount FROM PAYMENT1 WHERE `Status` = "Cleared"
UNION ALL
SELECT Amount FROM PAYMENT2 WHERE `Status` = "Cleared"
UNION ALL
SELECT Amount FROM PAYMENT3 WHERE `Status` = "Cleared") as Cf)
- (SELECT SUM(Price) AS TotalSales
FROM PROPERTY
WHERE Status = "Sold") as Result;
Here's the SQL Fiddle so that you can play with test data: http://sqlfiddle.com/#!2/18677/11
You can use SELECT ... INTO ..., in your case:
SELECT SUM(Cf.Amount) AS ClearedFunds
FROM (
SELECT Amount FROM PAYMENT1 WHERE `Status` = "Cleared"
UNION ALL
SELECT Amount FROM PAYMENT2 WHERE `Status` = "Cleared"
UNION ALL
SELECT Amount FROM PAYMENT3 WHERE `Status` = "Cleared") INTO #cf;
SELECT SUM(Price) AS TotalSales
FROM PROPERTY
WHERE Status = “Sold” INTO #ts;
Then you can substract or use them in any other query, like this:
SELECT #ts - #cf;
Are you looking for this?
SELECT C.ClearedFunds - P.TotalSales
FROM (
SELECT SUM(Cf.Amount) AS ClearedFunds
FROM (
SELECT Amount FROM PAYMENT1 WHERE `Status` = "Cleared"
UNION ALL
SELECT Amount FROM PAYMENT2 WHERE `Status` = "Cleared"
UNION ALL
SELECT Amount FROM PAYMENT3 WHERE `Status` = "Cleared") AS Cf) C,
(SELECT SUM(Price) AS TotalSales
FROM PROPERTY
WHERE Status = “Sold”) P
;

mysql date-format returns null

I have the following SQL query. It returns NULL for the 'invoice_date'.
SELECT * , fk_uid AS userId, fk_ivid AS invoice_uid, (
SELECT company
FROM tbl_users
WHERE pk_uid = userId
) AS invoice_customer, (
SELECT DATE_FORMAT( '%d/%m/%y', purchased ) AS invoice_date
FROM _invoices
WHERE invoice_uid = invoice_uid
LIMIT 1
) AS invoice_date
FROM tbl_statement_items
WHERE statement_generated = '1'
AND fk_statementId = '1'
LIMIT 0 , 30
Any help would be appriciated.
Thanks
You have inverted date_format parameters order.