Here is my query,
SELECT
`h`.`hotel_id`,
(
SELECT COUNT(room_id)
FROM
`abserve_hotel_rooms` AS `rm`
WHERE
`rm`.`adults_count` >= "1" AND `rm`.`room_count` >= "1" AND "Available" = IF(
check_in_time = '2016-03-15',
'Unavailable',
(
IF(
'2016-03-15' > check_in_time,
(
IF(
'2016-03-15' < check_out_time,
'Unavailable',
'Available'
)
),
(
IF(
'2016-03-22' > check_in_time,
'Unavailable',
'Available'
)
)
)
)
) AND `room_prize` BETWEEN '174' AND '600' AND `rm`.`hotel_id` = `h`.`hotel_id`
) AS `avail_room_count`,
(
SELECT MIN(room_prize)
FROM
`abserve_hotel_rooms` AS `rm`
WHERE
`rm`.`adults_count` >= "1" AND `rm`.`room_count` >= "1" AND "Available" = IF(
check_in_time = '2016-03-15',
'Unavailable',
(
IF(
'2016-03-15' > check_in_time,
(
IF(
'2016-03-15' < check_out_time,
'Unavailable',
'Available'
)
),
(
IF(
'2016-03-22' > check_in_time,
'Unavailable',
'Available'
)
)
)
)
) AND `room_prize` BETWEEN '174' AND '600' AND `rm`.`hotel_id` = `h`.`hotel_id`
) AS `min_val`
FROM
`abserve_hotels` AS `h`
WHERE
1 AND `city` = "madurai" AND `country` = "india"
It totally return one column values from my table abserve_hotels which is hotel_id with extra two alias columns such as avail_room_count and min_val..
And I wrote those in a subquery..
Here I have to check a condition WHERE min_val IS NOT NULL .i.e; if min_val having NULL value I have to restrict it
How can I do this..
And this is my table
hotel_id avail_room_count min_val
1 0 NULL
2 0 NULL
Here I need to restrict these NULL values..
Someone please help me ..
Add a HAVING clause at the end:
HAVING min_val IS NOT NULL
The new query after WHERE looks like:
WHERE
1 AND `city` = "madurai" AND `country` = "india"
HAVING min_val IS NOT NULL
Your query is overly complex and can be much simplified:
The two correlated sub queries are exactly the same, except for the SELECT list (MIN versus COUNT), so they could be combined into one;
The aggregation done by the sub query can be done in the main query;
The condition for checking availability can be written much shorter.
In fact, you can do all of what you need with the following query:
SELECT h.hotel_id,
COUNT(rm.room_id) as avail_room_count,
MIN(rm.room_prize) AS min_val
FROM abserve_hotels AS h
INNER JOIN abserve_hotel_rooms AS rm
ON rm.hotel_id = h.hotel_id
WHERE h.city = "madurai"
AND h.country = "india"
AND rm.adults_count >= 1
AND rm.room_count >= 1
AND rm.room_prize BETWEEN 174 AND 600
AND ( rm.check_in_time >= '2016-03-22'
OR rm.check_out_time <= '2016-03-15'
OR rm.check_in_time IS NULL)
GROUP BY h.hotel_id
Because the INNER JOIN requires at least one match, you can already be sure that min_val will never be NULL.
The check for availability is just as simple as:
( rm.check_in_time >= '2016-03-22'
OR rm.check_out_time <= '2016-03-15'
OR rm.check_in_time IS NULL)
The three parts of that condition mean:
The reservation for this room is future and does not overlap with this week;
The reservation for this room is in the past, the room is free today at the latest;
The room has no known reservation.
In all three cases the room is available for reservation for the concerned week.
Related
I'm working on a big query in SQL (MySQL 5.7) to calculate aggregated columns based on raw values in my table. I've created several aggregated columns (see attached screenshot and SQL) and I now need to create a conversion_percent column for each tlp_aff_id in my query.
This conversion_percent should be a division of the aggregated JoinedSessions.total_sessions and COUNT(Report.tlp_aff_id) as leads_total.
My current SQL:
SELECT
# Application details
Report.tlp_aff_id,
# Revenue
JoinedRevenue.total_revenue,
# Commission
JoinedCommission.total_commission,
# Profit
JoinedProfit.total_profit,
# Sessions
JoinedSessions.total_sessions,
# Submits
COUNT(Report.tlp_aff_id) as total_submits,
# Leads
COUNT(Report.tlp_aff_id) as leads_total,
SUM(case when Report.application_result = 'Accepted' then 1 else 0 end) leads_accepted,
SUM(case when Report.application_result = 'Rejected' then 1 else 0 end) leads_rejected
# Conversion percent
# JoinedConversion.conversion_percent
FROM
tlp_payout_report_minute AS Report
INNER JOIN
(
SELECT
JoinedRevenue.tlp_aff_id,
JoinedRevenue.minute_rounded_timestamp,
SUM(commission) AS total_revenue
FROM
tlp_payout_report_minute AS JoinedRevenue
WHERE
JoinedRevenue.minute_rounded_timestamp >= 1664841600
AND
JoinedRevenue.minute_rounded_timestamp <= 1664927999
GROUP BY
JoinedRevenue.tlp_aff_id
) AS JoinedRevenue
ON JoinedRevenue.tlp_aff_id = Report.tlp_aff_id
INNER JOIN
(
SELECT
ReportCommission.tlp_aff_id,
ReportCommission.seller_code,
ReportCommission.minute_rounded_timestamp,
SUM(commission) AS total_commission
FROM
tlp_payout_report_minute AS ReportCommission
WHERE
ReportCommission.minute_rounded_timestamp >= 1664841600
AND
ReportCommission.minute_rounded_timestamp <= 1664927999
AND
ReportCommission.seller_code != 44
GROUP BY
ReportCommission.tlp_aff_id
) AS JoinedCommission
ON JoinedCommission.tlp_aff_id = Report.tlp_aff_id
INNER JOIN
(
SELECT
ReportProfit.tlp_aff_id,
ReportProfit.seller_code,
ReportProfit.application_result,
ReportProfit.minute_rounded_timestamp,
SUM(commission) AS total_profit
FROM
tlp_payout_report_minute AS ReportProfit
WHERE
ReportProfit.minute_rounded_timestamp >= 1664841600
AND
ReportProfit.minute_rounded_timestamp <= 1664927999
AND
ReportProfit.application_result = 'Accepted'
AND
ReportProfit.seller_code = 44
GROUP BY
ReportProfit.tlp_aff_id
) AS JoinedProfit
ON JoinedProfit.tlp_aff_id = Report.tlp_aff_id
INNER JOIN
(
SELECT
Conversion.aff_id,
Conversion.conversion_type,
COUNT(Conversion.ip_address) as total_sessions
FROM
tlp_conversions AS Conversion
WHERE
Conversion.conversion_time >= '2022-10-04 00:00:00'
AND
Conversion.conversion_time <= '2022-10-04 23:59:59'
AND
Conversion.aff_id IS NOT NULL
AND
Conversion.conversion_type = 2
GROUP BY
Conversion.aff_id
) AS JoinedSessions
ON JoinedSessions.aff_id = Report.tlp_aff_id
WHERE
Report.minute_rounded_timestamp >= 1664841600
AND
Report.minute_rounded_timestamp <= 1664927999
GROUP BY
Report.tlp_aff_id
ORDER BY
JoinedRevenue.total_revenue DESC
I'm thinking something along the lines of:
INNER JOIN
(
...
) AS JoinedConversion
ON JoinedConversion.aff_id = Report.tlp_aff_id
But I don't think this is necessary for conversion_percent.
What's the right approach here?
I'm listing out orders data based on this query. This query basically pulls the recurring orders data from the table. I'm also using some dropdown and a input field to search / filter query results.
SELECT
orders.id,
parent_id,
(
SELECT
COUNT(*)
FROM
orders o
WHERE
o.parent_id = orders.id
) AS recurring_order_count,
shopify_order_type,
shopify_order_id,
shopify_order_customer_ID,
coupon_code AS coupon,
FORMAT(shopify_order_total_price, 2) AS shopify_order_total_price,
FORMAT(
shopify_order_subtotal_price,
2
) AS shopify_order_subtotal_price,
FORMAT(
shopify_order_total_line_items_price,
2
) AS shopify_order_total_line_items_price,
FORMAT(commission_amount, 2) AS commission_amount,
(
CASE WHEN is_paid = 0 THEN 'No' WHEN is_paid = 1 THEN 'Yes' ELSE 'Rejected'
END
) AS is_paid,
(
CASE WHEN is_invoice_generated = 1 THEN 'Pending' ELSE 'Invoice Generated'
END
) AS is_invoice_generated,
DATE_FORMAT(
shopify_order_created_at,
'%m-%d-%Y'
) AS shopify_order_created_at,
(
CASE WHEN is_paused = 0 THEN 'Running' ELSE 'Paused'
END
) AS is_paused,
DATE_FORMAT(
shopify_recurring_date,
'%m-%d-%Y'
) AS shopify_recurring_date
FROM
`orders`
WHERE
coupon_code LIKE '%GERALD8314%' OR shopify_order_id LIKE '%GERALD8314%' OR(
CASE WHEN is_paid = 0 THEN 'No' WHEN is_paid = 1 THEN 'Yes' ELSE 'Rejected'
END
) LIKE '%GERALD8314%' OR(
CASE WHEN is_invoice_generated = 1 THEN 'Pending' ELSE 'Invoice Generated'
END
) LIKE '%GERALD8314%' OR DATE_FORMAT(
shopify_order_created_at,
'%m-%d-%Y'
) LIKE '%GERALD8314%' OR(
CASE WHEN is_paused = 0 THEN 'Running' ELSE 'Paused'
END
) LIKE '%GERALD8314%' OR DATE_FORMAT(
shopify_recurring_date,
'%m-%d-%Y'
) LIKE '%GERALD8314%' AND DATE_FORMAT(
shopify_order_created_at,
'%Y-%m-%d'
) BETWEEN ? AND ?
GROUP BY
`id`
HAVING
parent_id = 0 AND shopify_order_type = 1
ORDER BY
`id`
DESC
LIMIT 10 OFFSET 0
Is this query optimized? Is this SELECT COUNT(*) FROM orders WHERE o.parent_id = orders.id AS recurring_order_count line most expensive in terms of query execution speed? Is there anything I should take care to improve the query speed here? Please advise.
OR and LIKE with leading wildcard are terrible for performance. Consider having a FULLTEXT index across the relevant columns. If it is practical, it will be immensely faster.
WHERE coupon_code LIKE '%GERALD8314%'
OR shopify_order_id LIKE '%GERALD8314%' OR( CASE WHEN is_paid = 0 THEN 'No' WHEN is_paid = 1 THEN 'Yes' ELSE 'Rejected' END ) LIKE '%GERALD8314%' OR( CASE WHEN is_invoice_generated = 1 THEN 'Pending' ELSE 'Invoice Generated' END ) LIKE '%GERALD8314%'
OR DATE_FORMAT( shopify_order_created_at, '%m-%d-%Y' ) LIKE '%GERALD8314%' OR( CASE WHEN is_paused = 0 THEN 'Running' ELSE 'Paused' END ) LIKE '%GERALD8314%'
OR DATE_FORMAT( shopify_recurring_date, '%m-%d-%Y' ) LIKE '%GERALD8314%'
AND DATE_FORMAT( shopify_order_created_at, '%Y-%m-%d' ) BETWEEN ? AND ?
Also, there may be surprises in the results. Note that you have
a OR b OR c AND d
which is the same as
a OR b OR (c AND d)
I suspect you wanted
(a OR b OR c) AND d
I think the GROUP BY is unnecessary. And the HAVING clauses can be merged into the WHERE.
GROUP BY `id`
HAVING parent_id = 0
AND shopify_order_type = 1
ORDER BY `id` DESC
This has multiple issues:
DATE_FORMAT( shopify_order_created_at, '%Y-%m-%d' ) BETWEEN ? AND ?
BETWEEN is "inclusive". The way you have written the query, it will include the entire ending day. This may not be what you wanted.
Assuming the variable is a DATE or DATETIME, it can be simplified to
shopify_order_created_at BETWEEN ? AND ?
There may be more tips; fix these then come back for more.
I get error
SQL Error (1055): Expression #7 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'ifu.amount' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
after migrating to mysql 8.0 from 5.6. I know that it can be easily fixed by disabling ONLY_FULL_GROUP_BY flag, but I want it to be more compatible with mysql 8.0. So question is if I would add ifu.amount to GROUP BY it should work perfetcly fine and I won't miss any query results or anything? Now without GROUP BY ifu.amount MySQL code looks like:
select
`i`.`id` AS `institution_id`,
`i`.`name` AS `institution_name`,
`cr`.`check_date` AS `check_date`,
sum(
(
case when (`cr`.`status` = '1') then 1 else 0 end
)
) AS `can_accept`,
sum(
(
case when (`cr`.`status` = '0') then 1 else 0 end
)
) AS `cannot_accept`,(
sum(
(
case when (`cr`.`status` = '1') then 1 else 0 end
)
) + sum(
(
case when (`cr`.`status` = '0') then 1 else 0 end
)
)
) AS `suma`,
`ifu`.`amount` AS `amount`,
round(
(
(
(
(
sum(
(
case when (`cr`.`status` = '1') then 1 else 0 end
)
) * 100
) / (
sum(
(
case when (`cr`.`status` = '1') then 1 else 0 end
)
) + sum(
(
case when (`cr`.`status` = '0') then 1 else 0 end
)
)
)
) * `ifu`.`amount`
) * 0.01
),
2
) AS `financed_amount`
from
(
(
(
`check_results` `cr`
join `family_doctors` `fd` on((`fd`.`id` = `cr`.`doctor_id`))
)
join `institutions` `i` on((`i`.`id` = `fd`.`institution_id`))
)
join `institutions_funding` `ifu` on((`ifu`.`institution_id` = `i`.`id`))
)
where
(`cr`.`status` in (1, 0))
group by
`i`.`id`,
`i`.`name`,
`cr`.`check_date`
Thanks for help in advance!
Include amount in your group by clause.
where
(`cr`.`status` in (1, 0))
group by
`i`.`id`,
`i`.`name`,
`cr`.`check_date`,
`ifu`.`amount`
if amount is excluded on your group by clause, this will get the amount that corresponds on your id, name and check date in ascending order (default).
or
min(`ifu`.`amount`) as `amount`.
Table structure:
Table Structure http://imagebin.org/index.php?mode=image&id=238883
I want to fetch data from both the tables which satisfy some of the conditions like
WHERE batch='2009', sex='male',course='B.Tech', branch='cs', xth_percent>60,
x2percent>60, gradpercent>60 and (if ranktype='other' ) then
no._of_not_null_semester>number elseifranktype='Leet') then
no._of_not_null_semester>number-2
sem 1-8 contains percentage for 8 semesters, and I want to filter results for each student if they have cleared 3 semesters or 4 semester i.e. not null values out of 8 values
no._of_not_null_semester
needs to be calculated, it is not a part of database, need help with that as well.
Required Query
SELECT * FROM student_test
INNER JOIN master_test ON student_test.id=master_test.id
WHERE sex='male' and batch='2009' and course='B.Tech'
and xthpercent>60 and x2percent>60 and
WHEN ranktype='Leet' THEN
SUM(CASE WHEN sem1 IS NOT NULL THEN 1 ELSE 0
WHEN sem2 IS NOT NULL THEN 1 ELSE 0
WHEN sem3 IS NOT NULL THEN 1 ELSE 0
WHEN sem4 IS NOT NULL THEN 1 ELSE 0
WHEN sem5 IS NOT NULL THEN 1 ELSE 0) >2
ELSE
SUM(CASE WHEN sem1 IS NOT NULL THEN 1 ELSE 0
WHEN sem2 S NOT NULL THEN 1 ELSE 0
WHEN sem3 IS NOT NULL THEN 1 ELSE 0
WHEN sem4 IS NOT NULL THEN 1 ELSE 0
WHEN sem5 IS NOT NULL THEN 1 ELSE 0) >4
Without changing the structure you can't use COUNT to achieve this.
One way to solve the problem would be to create a semester table which would contain a row for each finished semester for each student. This would have a foreign key pointing to test_student.id and you could use COUNT(semester.id)
If that is an option for you, it would be the best solution.
EDIT:
Check this out, didn't test the query but should work generally
I decided to do the math in the select itself to prevent calculating the same thing twice.
The HAVING conditions are applied after your result is ready to deliver, just before a LIMIT.
In terms of speed optimization you could try and move the sSum block into the WHERE condition just like you had it before. Probably it doesn't make much of a difference
SUM() does not work because it is an aggregate function which summarizes values in a column
I did some changes to your query in addition:
don't SELECT *, select specific fields and add a table identifier. ( in this case I used the aliases s for student_test AND m for master_test )
you put s.batch = '2009' into single quotes - if the field batch is an integer field, you should use s.batch = 2009, which would prevent MySQL from casting every single row to string to be able to compare it (int = int much faster than cast(int as varchar) = varchar) same about the other numeric values in your table
The Query:
SELECT
s.id,
s.sex,
s.course,
s.branch,
(
IF ( m.sem1 IS NOT NULL, 1, 0 ) +
IF ( m.sem2 IS NOT NULL, 1, 0 ) +
IF ( m.sem3 IS NOT NULL, 1, 0 ) +
IF ( m.sem4 IS NOT NULL, 1, 0 ) +
IF ( m.sem5 IS NOT NULL, 1, 0 ) +
IF ( m.sem6 IS NOT NULL, 1, 0 ) +
IF ( m.sem7 IS NOT NULL, 1, 0 ) +
IF ( m.sem8 IS NOT NULL, 1, 0 )
) AS sSum
FROM
student_test s
INNER JOIN master_test m ON m.id = s.id
WHERE
s.sex = 'male'
AND
s.batch = '2009' # I dont see this field in your database diagram!?
AND
s.course = 'B.Tech'
AND
m.xthpercent > 60
AND
m.x2percent > 60
HAVING
(
m.ranktype = 'OTHER'
AND
sSum > 4
)
OR
(
m.ranktype = 'LEET'
AND
sSum > 2
)
If you're generally interested in learning database design and usage I found an very interesting opportunity for you.
Stanford University offers a free database class "Introduction to databases". This is free and will cost you approx. 2 hours a week for 3 weeks, final exam included.
https://class2go.stanford.edu/db/Winter2013/preview/
SELECT
s.id,
s.sex,
s.course,
s.deptt,
m1.id,
m1.xthpercent,
m1.x2percent,
m1.sem1,
m1.sem2,
m1.sem3,
m1.ranktype,
m1.sem4,
m1.sem5,
m1.sem6,
m1.sem7,
m1.sem8,
m1.sSum
FROM
student_test s
INNER JOIN(SELECT m.id,
m.xthpercent,
m.x2percent,
m.sem1,
m.sem2,
m.sem3,
m.ranktype,
m.sem4,
m.sem5,
m.sem6,
m.sem7,
m.sem8,
( IF ( ceil(m.sem1)>0, 1, 0 ) +
IF ( ceil(m.sem2)>0, 1, 0 ) +
IF ( ceil(m.sem3)>0, 1, 0 ) +
IF ( ceil(m.sem4)>0, 1, 0 ) +
IF ( ceil(m.sem5)>0, 1, 0 ) +
IF ( ceil(m.sem6)>0, 1, 0 ) +
IF ( ceil(m.sem7)>0, 1, 0 ) +
IF ( ceil(m.sem8)>0, 1, 0 )
) AS sSum FROM master_test m
WHERE m.xthpercent>60 and
m.x2percent>60
HAVING (m.ranktype='Leet' AND sSum>2 )
OR
(m.ranktype != 'Leet') AND sSum>4 )
as m1 ON m1.id = s.id
WHERE
s.sex='Male'
and
s.course='B.Tech'
and
s.deptt='ELE'
This is the query finally I'm using, Love that query :)
I am trying to combine these 2 queries in such a way to determine who the PI is that owns equipment (>$100K value). I have the ability to find all the equipment one PI owns that is greater then 100k. I also have the ability to see all the PIs. I just cannot get these 2 queries to combine. I have tried with a WHERE subquery and an EXIST subquery. I want to be able to find all the equipment (matched with its PI owner) where the PI exists in query #2.
Query #1 for finding equipment of a specific PI
select Account_No,Inventory_No,Building_No,Room_No,CDDEPT,Location,Normalized_MFG,Manufacturer_Name,Normalized_Model,Name,Serial_Code,CONCAT( '$', FORMAT( Cost, 2 ) ) as Cost, Equipment_Inventory_Normalized.Active
from Temp_Equipment_Inventory.Equipment_Inventory_Normalized, `paul`.`ROOM`, `paul`.`BLDG`, `paul`.`LABORATORY`, `paul`.`PERSON`
where (`PERSON`.`ID` = `LABORATORY`.`PI_ID` OR `PERSON`.`ID` = `LABORATORY`.`SUPV_ID`)
AND `LABORATORY`.`RM_ID` = `ROOM`.`ID`
AND `LABORATORY`.`ACTIVE` = '1'
AND `ROOM`.`BLDG_ID` = `BLDG`.`ID`
AND ((
`BLDG`.`BLDGNUM` = Equipment_Inventory_Normalized.Building_No
AND Equipment_Inventory_Normalized.Actual_Building IS NULL
AND (`BLDG`.`BLDGNUM` != '1023' AND `LABORATORY`.`OTHER_LEVEL` != '1' AND `ROOM`.`RMNUM` != '0199')
)OR (
`BLDG`.`BLDGNUM` = Equipment_Inventory_Normalized.Actual_Building AND
(`BLDG`.`BLDGNUM` != '1023' AND `LABORATORY`.`OTHER_LEVEL` != '1' AND `ROOM`.`RMNUM` != '0199')
))
AND ((
`ROOM`.`RMNUM` = Equipment_Inventory_Normalized.Room_No
AND Equipment_Inventory_Normalized.Actual_Room IS NULL
)OR (
`ROOM`.`RMNUM` = Equipment_Inventory_Normalized.Actual_Room
))
AND Equipment_Inventory_Normalized.Active !=0
AND SurplusPending != '1'
AND Cost >= 100000
AND `PERSON`.`CANNUM`='810010787'
Query 2 that finds all the PIs
select distinct i.CAN
from CGWarehouse.CCGV10WC w
inner join CGWarehouse.CCGV10IC i
on w.PROJECT_NUMBER=i.SPONSORED_PROJECT
and w.SEQUENCE_NUMBER=i.PROJECT_SEQUENCE
where w.STATUS='A'
and i.PRIN_INVEST_CODE='Y'
and i.DEL_CODE!='Y'
and i.CAN IS NOT NULL
Perhaps you're looking for the IN keyword in your WHERE clause?
Forgive me, but I had to clean up the formatting of your query a little...it's kinda my OCD thing:
SELECT
Account_No,
Inventory_No,
Building_No,
Room_No,
CDDEPT,
Location,
Normalized_MFG,
Manufacturer_Name,
Normalized_Model,
Name,
Serial_Code,
CONCAT('$', FORMAT( Cost, 2 )) AS Cost,
Equipment_Inventory_Normalized.Active
FROM
Temp_Equipment_Inventory.Equipment_Inventory_Normalized a,
`paul`.`ROOM`,
`paul`.`BLDG`,
`paul`.`LABORATORY`,
`paul`.`PERSON`
WHERE
(`PERSON`.`ID` = `LABORATORY`.`PI_ID` OR `PERSON`.`ID` = `LABORATORY`.`SUPV_ID`)
AND `LABORATORY`.`RM_ID` = `ROOM`.`ID`
AND `LABORATORY`.`ACTIVE` = '1'
AND `ROOM`.`BLDG_ID` = `BLDG`.`ID`
AND (
(
`BLDG`.`BLDGNUM` = Equipment_Inventory_Normalized.Building_No
AND Equipment_Inventory_Normalized.Actual_Building IS NULL
AND `BLDG`.`BLDGNUM` != '1023'
AND `LABORATORY`.`OTHER_LEVEL` != '1'
AND `ROOM`.`RMNUM` != '0199'
) OR (
`BLDG`.`BLDGNUM` = Equipment_Inventory_Normalized.Actual_Building
AND `BLDG`.`BLDGNUM` != '1023'
AND `LABORATORY`.`OTHER_LEVEL` != '1'
AND `ROOM`.`RMNUM` != '0199'
)
)
AND (
(
`ROOM`.`RMNUM` = Equipment_Inventory_Normalized.Room_No
AND Equipment_Inventory_Normalized.Actual_Room IS NULL
) OR (
`ROOM`.`RMNUM` = Equipment_Inventory_Normalized.Actual_Room
)
)
AND Equipment_Inventory_Normalized.Active !=0
AND SurplusPending != '1'
AND Cost >= 100000
AND `PERSON`.`CANNUM` IN ( /* this assumes that the `PERSON`.`CANNUM` column matches up with the CGWarehouse.CCGV10IC.CAN column */
SELECT DISTINCT i.CAN
FROM
CGWarehouse.CCGV10WC w
INNER JOIN CGWarehouse.CCGV10IC i ON w.PROJECT_NUMBER=i.SPONSORED_PROJECT AND w.SEQUENCE_NUMBER=i.PROJECT_SEQUENCE
WHERE
w.STATUS='A'
AND i.PRIN_INVEST_CODE='Y'
AND i.DEL_CODE!='Y'
AND i.CAN IS NOT NULL
)