How to use if condition in where clause in mysql - mysql

I have a query that fetch records from two table. I want if condition in where clause with and operator.
Here is my code :
SELECT sfo.customer_id, sfo.increment_id FROM sales_flat_order sfo
INNER JOIN marketplace_partnertype mptype ON sfo.customer_id = mptype.partner_id
WHERE (mptype.type = 'free' AND sfo.status='complete') AND IF #mptype.type=='free' THEN ((DATE( updated_at ) = DATE_SUB( CURDATE( ) , INTERVAL 5 DAY ))ELSE (DATE( updated_at ) = DATE_SUB( CURDATE( ) , INTERVAL 3 DAY );
It shows syntax error near IF #mptype.type=='free'.
It should be appreciable if some help to solve this issues.

Syntax of If condition is:
IF(<cond-expr>, <then-expr>, <else-expr>)
If we change the condition it will be like :-
AND IF (#mptype.type=='free', (DATE( updated_at ) = DATE_SUB( CURDATE( ) , INTERVAL 5 DAY )) ,(DATE( updated_at ) = DATE_SUB( CURDATE( ) , INTERVAL 3 DAY ))
Query will look like:
SELECT sfo.customer_id, sfo.increment_id FROM sales_flat_order sfo
INNER JOIN marketplace_partnertype mptype ON sfo.customer_id = mptype.partner_id
WHERE (mptype.type = 'free' AND sfo.status='complete')AND IF (#mptype.type=='free', (DATE( updated_at ) = DATE_SUB( CURDATE( ) , INTERVAL 5 DAY )) ,(DATE( updated_at ) = DATE_SUB( CURDATE( ) , INTERVAL 3 DAY )))

The syntax is not correct, you can use case-when condition in the where condition as
SELECT sfo.customer_id, sfo.increment_id FROM sales_flat_order sfo
INNER JOIN marketplace_partnertype mptype ON sfo.customer_id = mptype.partner_id
WHERE (mptype.type = 'free' AND sfo.status='complete')
and
case
when #mptype.type = 'free' then DATE( updated_at ) = DATE_SUB( CURDATE( ) , INTERVAL 5 DAY )
else DATE( updated_at ) = DATE_SUB( CURDATE( ) , INTERVAL 3 DAY )
end

There's no need to use IF or CASE WHEN:
SELECT
sfo.customer_id,
sfo.increment_id
FROM
sales_flat_order sfo INNER JOIN marketplace_partnertype mptype
ON sfo.customer_id = mptype.partner_id
WHERE
(mptype.type = 'free' AND DATE(updated_at) = DATE_SUB(CURDATE(), INTERVAL 5 DAY)
OR (mptype.type = 'complete' AND DATE(updated_at) = DATE_SUB(CURDATE(), INTERVAL 3 DAY);
but if you want to use case when you could do it this way:
WHERE
mptype.type IN ('free', 'complete')
AND DATE(updated_at) = DATE_SUB(CURDATE(), INTERVAL CASE WHEN mptype.type='free' THEN 3 ELSE 5 END DAY)

Related

MYSQL Subtracting two SELECT Queries

Using MYSQL, I have written two big SELECT queries combined by a UNION, to get 2 rows, where the first row is the count for the current month, and the second row is the count for the previous month. The Query is as follows:
select * from
(select count(*) as type1 from table_x where nationality_id = 23 and month(START_DATE) = month(now())) as t1,
(select count(*) as type2 from table_x where nationality_id = 24 and month(START_DATE) = month(now())) as t2,
(select count(*) as type3 from table_x where nationality_id = 25 and month(START_DATE) = month(now())) as t3,
(select count(*) as type4 from table_x where nationality_id = 26 and month(START_DATE) = month(now())) as t4
UNION
select * from
(select count(*) as type1 from table_x where nationality_id = 23 and month(START_DATE) = month(now() - INTERVAL 1 MONTH)) as t1,
(select count(*) as type2 from table_x where nationality_id = 24 and month(START_DATE) = month(now() - INTERVAL 1 MONTH)) as t2,
(select count(*) as type3 from table_x where nationality_id = 25 and month(START_DATE) = month(now() - INTERVAL 1 MONTH)) as t3,
(select count(*) as type4 from table_x where nationality_id = 26 and month(START_DATE) = month(now() - INTERVAL 1 MONTH)) as t4
I want to add a third row, which is the difference between row 2 and row 1.
How can I do this with my current query?
You are obviously doing a compare between current and prior month. So, I would start with my inner pre-query aggregate getting only those transactions >= the first of the prior month AND the records within the nationality IDs you are looking for.
The inner date_sub() of DAYOFMONTH() -1 day gives you the first of the CURRENT month. By subtracting one more month, gives you the first of the LAST month.
Now you can aggregate the totals per nationality compared to current month or not. That inner query gives you all begin and end counts. Now that is wrapped to the outer and you can get all the counts in addition to the differences... Obviously you can change the column names respectively.
select
PQ.*,
PQ.ThisMonth23 - PQ.LastMonth23 = Diff23,
PQ.ThisMonth24 - PQ.LastMonth24 = Diff24,
PQ.ThisMonth25 - PQ.LastMonth25 = Diff25,
PQ.ThisMonth26 - PQ.LastMonth26 = Diff26
from
( select
sum( case when t.Nationality_id = 23 and month( t.StartDate ) = month( now()) then 1 else 0 end ) ThisMonth23,
sum( case when t.Nationality_id = 24 and month( t.StartDate ) = month( now()) then 1 else 0 end ) ThisMonth24,
sum( case when t.Nationality_id = 25 and month( t.StartDate ) = month( now()) then 1 else 0 end ) ThisMonth25,
sum( case when t.Nationality_id = 26 and month( t.StartDate ) = month( now()) then 1 else 0 end ) ThisMonth26,
sum( case when t.Nationality_id = 23 and month( t.StartDate ) != month( now()) then 1 else 0 end ) LastMonth23,
sum( case when t.Nationality_id = 24 and month( t.StartDate ) != month( now()) then 1 else 0 end ) LastMonth24,
sum( case when t.Nationality_id = 25 and month( t.StartDate ) != month( now()) then 1 else 0 end ) LastMonth25,
sum( case when t.Nationality_id = 26 and month( t.StartDate ) != month( now()) then 1 else 0 end ) LastMonth26
from
table_x t
where
t.StartDate >= date_sub( date_sub( t.StartDate, interval DAYOFMONTH( t.StartDate ) -1 DAY ), interval 1 MONTH )
AND t.Nationality_id IN ( 23, 24, 25, 26 )
) PQ
I would just add that your query might be getting more than you think... You are asking for ALL records Ex: January REGARDLESS of the year, compared to ALL records December REGARDLESS of the year because all you are qualifying is based on the MONTH() and no YEAR() consideration. I am explicitly querying back only current and prior month.

UNION issue in select sub-query

In the below code, how do I combine MRR_Created with MRR_Destroyed in a UNION so it only shows the next number? Right now the query is correct but I don't need to see the increase/decrease separately.
select account.email, account.vip, datediff(now(), account.date_created) AS Age,
(select sum(account_subscription.next_invoice_price) as ActiveMRR
from account_subscription
where account_subscription.status = 'active'
and account_subscription.acctid = account.acctid
) as MRR,
(select count(account_subscription.subid) as Churn
from account_subscription
where account_subscription.date_created between DATE_ADD(NOW(), INTERVAL -2880 MINUTE) and NOW()
and account_subscription.date_closed between DATE_ADD(NOW(), INTERVAL -2880 MINUTE) and NOW()
and account_subscription.acctid = account.acctid
) as Churn,
(select sum(account_subscription.next_invoice_price) as MRR
from account_subscription
where date(account_subscription.date_created) = date(curdate())
and account_subscription.acctid = account.acctid
) as MRR_Created,
(select sum(account_subscription.next_invoice_price) as MRR
from account_subscription
where date(account_subscription.date_closed) = date(curdate())
and account_subscription.acctid = account.acctid
) as MRR_Destroyed,
concat("https://sitetest.com?ACCTID=",account.acctid) as URL
from account
where account.status = 'active'
and (
account.type in ('affiliate', 'customer', 'customer_freetrial', 'customer_duplicate', 'customer_match')
or account.type is null
)
group by account.acctid
order by MRR desc
Not sure if you really need a UNION here. Try replacing
(select sum(account_subscription.next_invoice_price) as MRR
from account_subscription
where date(account_subscription.date_created) = date(curdate())
and account_subscription.acctid = account.acctid
) as MRR_Created,
(select sum(account_subscription.next_invoice_price) as MRR
from account_subscription
where date(account_subscription.date_closed) = date(curdate())
and account_subscription.acctid = account.acctid
) as MRR_Destroyed,
with
(select sum(account_subscription.next_invoice_price) as MRR
from account_subscription
where (date(account_subscription.date_created) = date(curdate())
or date(account_subscription.date_closed) = date(curdate()))
and account_subscription.acctid = account.acctid
) as MRR_Created,
Hope this helps!

MySQL join tables with subquery

I have this crazy query below. I want to organize them but don't know how.
Can someone help me run this query? I want to join the 5 sub-query tables below and at the end, the result would be a table displaying line item_id with last5days, last10days, last30days, last60days, last90days.
Thanks a bunch!
Select q1.line_item_id,
q1.domains as 'last5days',
q2.domains as 'last10days',
q3.domains as 'last30days',
q4.dpmains as 'last60days',
q5.domains as 'last90days'
From q1
Join q2 on q1.line_item_id = q2.line_item_id
Join q3 on q1.line_item_id = q3.line_item_id
Join q4 on q1.line_item_id = q4.line_item_id
Join q4 on q1.line_item_id = q5.line_item_id
select q1.line_item_id, count(*) domains
from (
select distinct line_item_id, domain
from rpt_domain_by_campaign
where event_date between DATE_SUB(curdate(), INTERVAL 5 DAY)
and now()
) q1
group by q1.line_item_id
select q1.line_item_id, count(*) domains
from (
select distinct line_item_id, domain
from rpt_domain_by_campaign
where event_date between DATE_SUB(curdate(), INTERVAL 10 DAY)
and now()
) q2
group by q1.line_item_id
select q1.line_item_id, count(*) domains
from (
select distinct line_item_id, domain
from rpt_domain_by_campaign
where event_date between DATE_SUB(curdate(), INTERVAL 30 DAY)
and now()
) q3
group by q1.line_item_id
select q1.line_item_id, count(*) domains
from (
select distinct line_item_id, domain
from rpt_domain_by_campaign
where event_date between DATE_SUB(curdate(), INTERVAL 60 DAY)
and now()
) q4
group by q1.line_item_id
select q1.line_item_id, count(*) domains
from (
select distinct line_item_id, domain
from rpt_domain_by_campaign
where event_date between DATE_SUB(curdate(), INTERVAL 90 DAY)
and now()
) q5
group by q1.line_item_id
Just use sum and case make more easy:
select line_item_id,
Sum( CASE WHEN DATEDIFF(curdate(), event_date) <= 5 then 1 ELSE 0 END ) 'last5days',
Sum( CASE WHEN DATEDIFF(curdate(), event_date) <= 10 then 1 ELSE 0 END ) 'last10days',
Sum( CASE WHEN DATEDIFF(curdate(), event_date) <= 30 then 1 ELSE 0 END ) 'last30days',
Sum( CASE WHEN DATEDIFF(curdate(), event_date) <= 60 then 1 ELSE 0 END ) 'last60days',
Sum( CASE WHEN DATEDIFF(curdate(), event_date) <= 90 then 1 ELSE 0 END ) 'last90days'
from rpt_domain_by_campaign
Group by line_item_id
I recommend using count(distinct...) to avoid the extra layer of nesting in each of your sub-queries.
I also recommend switching the order of sub-queries and using outer joins because not every line item with rows in the past 90 days will also have rows in the past 60 days, etc.
Try something like this:
Select q1.line_item_id,
q1.domains as last90days,
coalesce(q2.domains,0) as last60days,
coalesce(q3.domains,0) as last30days,
coalesce(q4.domains,0) as last10days,
coalesce(q5.domains,0) as last5days
from
(
select line_item_id, count(distinct domain) as domains
from rpt_domain_by_campaign
where event_date between DATE_SUB(curdate(), INTERVAL 90 DAY)
and now()
group by line_item_id
) q1
left outer join
(
select line_item_id, count(distinct domain) as domains
from rpt_domain_by_campaign
where event_date between DATE_SUB(curdate(), INTERVAL 60 DAY)
and now()
group by line_item_id
) q2 on q1.line_item_id = q2.line_item_id
left outer join
(
select line_item_id, count(distinct domain) as domains
from rpt_domain_by_campaign
where event_date between DATE_SUB(curdate(), INTERVAL 30 DAY)
and now()
group by line_item_id
) q3 on q1.line_item_id = q3.line_item_id
left outer join
(
select line_item_id, count(distinct domain) as domains
from rpt_domain_by_campaign
where event_date between DATE_SUB(curdate(), INTERVAL 10 DAY)
and now()
group by line_item_id
) q4 on q1.line_item_id = q4.line_item_id
left outer join
(
select line_item_id, count(distinct domain) as domains
from rpt_domain_by_campaign
where event_date between DATE_SUB(curdate(), INTERVAL 5 DAY)
and now()
group by line_item_id
) q5 on q1.line_item_id = q5.line_item_id
Just use group by max date
select line_item_id,
Sum( CASE WHEN DATEDIFF(curdate(), event_date) <= 5 then 1 ELSE 0 END ) 'last5days',
Sum( CASE WHEN DATEDIFF(curdate(), event_date) <= 10 then 1 ELSE 0 END ) 'last10days',
Sum( CASE WHEN DATEDIFF(curdate(), event_date) <= 30 then 1 ELSE 0 END ) 'last30days',
Sum( CASE WHEN DATEDIFF(curdate(), event_date) <= 60 then 1 ELSE 0 END ) 'last60days',
Sum( CASE WHEN DATEDIFF(curdate(), event_date) <= 90 then 1 ELSE 0 END ) 'last90days'
from
(
select line_item_id, max(event_date) event_date
from
rpt_domain_by_campaign
where event_date < curdate()
group by line_item_id, domain
) a
Group by line_item_id

SQL exception Parameter index out of range

I'm sending 4 values for the sql query through a jaggery script. Here is the sql query:
SELECT full_name , sum( amount ) AS total
FROM hourlyusage , user
WHERE DAY = DATE( DATE_SUB( NOW( ) , INTERVAL ? HOUR ) )
AND HOUR BETWEEN HOUR( DATE_SUB( NOW( ) , INTERVAL ? HOUR ) )
AND HOUR( DATE_SUB( NOW( ) , INTERVAL 1 HOUR ) )
AND hourlyusage.userIp = user.ip_address
AND (user.full_name LIKE '%?%' OR user.user_name LIKE '%?%') GROUP BY full_name
But it gives an exception like this.
Nested Exception:-
java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2).
What would be the reason for that?
SELECT full_name , sum( amount ) AS total
FROM hourlyusage , user
WHERE DAY = DATE( DATE_SUB( NOW( ) , INTERVAL ? HOUR ) )
AND HOUR BETWEEN HOUR( DATE_SUB( NOW( ) , INTERVAL ? HOUR ) )
AND HOUR( DATE_SUB( NOW( ) , INTERVAL 1 HOUR ) )
AND hourlyusage.userIp = user.ip_address
AND (user.full_name LIKE ? OR user.user_name LIKE ?) GROUP BY full_name
You cannot use wildcard in the sql query so try to remove the wildcard from the sql and add it to the value.As you have done '%?%' in sql says that you need global match.Do that in your value not in sql query.

select * WHERE status <> 'deleted' OR status <> 'completed' AND update_datetime < unix_timestamp(now() - interval 7 day)

I would like to pull all rows where the status column IS NOT marked 'deleted' AND where the status is marked 'completed' if the update_datetime column is older than 7 days (MySQL version 2013-04-11 11:22:44 ).
Here's my feeble and failed attempt:
WHERE
status <> 'deleted'
OR status <> 'completed'
AND update_datetime < unix_timestamp( now() - interval 7 day )
WHERE
status <> 'deleted'
AND (
(update_datetime < unix_timestamp( now() - interval 7 day ) AND status = 'completed')
OR (update_datetime >= unix_timestamp( now() - interval 7 day ))
)
If the update_datetime is a DATETIME column, use this instead:
WHERE
status <> 'deleted'
AND (
(update_datetime < DATE_SUB(NOW(), INTERVAL 7 day) AND status = 'completed')
OR (update_datetime >= DATE_SUB(NOW(), INTERVAL 7 day))
)
Do you mean this?
WHERE
(status <> 'deleted'
OR status <> 'completed')
AND update_datetime < unix_timestamp( now() - interval 7 day )
it is equal to
WHERE
(not status in ('deleted', 'completed'))
AND update_datetime < unix_timestamp( now() - interval 7 day )