issue combining two mysql queries - mysql

I have two queries I am looking to combine into one. This query will be called by backbone in a rails app. The final result should look like this. Thanks in advance.
Title Impressions Completed
Test 1234 500 34
SELECT title, count(*) as impressions FROM `stats`
WHERE `stats`.`user_id` = 2
AND (stats.event ='play' and videopos = '0')
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59')
GROUP BY title;
SELECT title, count(*) as completed FROM `stats`
WHERE `stats`.`user_id` = 2
AND (stats.event ='completed')
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59')
GROUP BY title;

try that :
SELECT title,(select count(*) FROM `stats` WHERE stats.event ='play' and videopos = '0' AND `stats`.`user_id` = 2 AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59') ) as impressions ,(select count(*) FROM `stats` WHERE stats.event ='completed' AND `stats`.`user_id` = 2 AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59') ) as completed
FROM `stats`
WHERE `stats`.`user_id` = 2
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59')
GROUP BY title;

If you just want to combine the result, use UNION/UNION ALL
SELECT title, count(*) as impressions FROM `stats`
WHERE `stats`.`user_id` = 2
AND (stats.event ='play' and videopos = '0')
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59')
GROUP BY title
UNION
SELECT title, count(*) as completed FROM `stats`
WHERE `stats`.`user_id` = 2
AND (stats.event ='completed')
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59')
GROUP BY title;

Try this :
SELECT title,
Sum(Case When `stats`.`user_id` = 2
AND (stats.event ='play' and videopos = '0')
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59' Then 1 Else 0 End)
as impressions ,
Sum(Case When `stats`.`user_id` = 2
AND (stats.event ='completed')
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59') Then 1 Else 0 End)
as completed
FROM `stats`
WHERE (`stats`.`user_id` = 2
AND (stats.event ='play' and videopos = '0')
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59') )
OR
(`stats`.`user_id` = 2
AND (stats.event ='completed')
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59') )
GROUP BY title;
btw, I am coming from ms-sql-server background but I checked on mysql case when syntax. And I typed in notepad, so untested. But I hope you catch the Sum Case When 1 0 idea and tweak it to your requirement..

I figured it out. This worked for me.
SELECT s.date as date, s.title as title,
count(F.id) as impressions,
count(D.event) as completed
FROM stats s
Left Join stats as F on s.id = F.id and F.event ='play' and F.videopos = '0'
Left Join stats as D on s.id = D.id and D.event = 'completed'
WHERE s.user_id = '2'
AND (s.date_time between '2014-03-08 00:00:00' and '2014-03-18 23:59:59')
AND s.title is not null
GROUP BY s.title

Related

sql group by with double conditions

I need to get the amount of distinct parent_ids that fill in one of the conditions below , grouped by day:
parent_ids that have both status = pending & processing
OR
parent_ids who have both status = canceled and processing.
I ve tried something similar to :
SELECT count(parent_id) as pencan, created_at, DATE_FORMAT(a.created_at, '%Y') AS year_key, DATE_FORMAT(a.created_at, '%m-%d') as day_key
FROM sales_flat_order_status_history
where created_at BETWEEN '2010-01-01 00:00:00' AND '2013-04-30 23:59:59'
GROUP BY created_at ,parent_id
HAVING SUM(status = 'processing')
AND SUM(status IN ('pending', 'cancelling'))
I think you just need to fix the group by:
SELECT DATE(created_at), count(parent_id) as pencan
FROM sales_flat_order_status_history
where created_at >= '2010-01-01' AND
created_at < '2013-05-01'
GROUP BY DATE(created_at) , parent_id
HAVING SUM(status = 'processing') AND
SUM(status IN ('pending', 'cancelling'))

How can I create this query?

I have this MySQL Query here:
SELECT
COUNT(*) ReleasePerMonth,
d.name as DevGroup_REGION
FROM
release_summary r
inner join
gti_server_info g
on r.gti_server_id = g.gti_server_id
inner join
dev_group d
on d.dev_group_id = g.dev_group_id
WHERE
r.testingFinishedOn_timestamp >= '2020-05-01 00:00:00'
AND r.testingFinishedOn_timestamp <= '2020-05-31 00:00:00'
AND r.test_type != 14
GROUP BY
d.name ;
Now, I want this to run for every month. That is,
r.testingFinishedOn_timestamp >= '2019-01-01 00:00:00'
AND r.testingFinishedOn_timestamp <= '2019-01-31 00:00:00'
and
r.testingFinishedOn_timestamp >= '2019-05-02 00:00:00'
AND r.testingFinishedOn_timestamp <= '2019-02-31 00:00:00'
Till end of year. Currently, I am doing this manually. Is there any way I can do it in an automated manner?
Clarification:
I'd want 12 seperate tables for each of the 12 months.
Try the following:
SELECT
YEAR(r.testingFinishedOn_timestamp) year,
MONTH(r.testingFinishedOn_timestamp) month,
COUNT(*) ReleasePerMonth,
d.name as DevGroup_REGION
FROM
release_summary r
inner join
gti_server_info g
on r.gti_server_id = g.gti_server_id
inner join
dev_group d
on d.dev_group_id = g.dev_group_id
WHERE
r.test_type != 14
GROUP BY
YEAR(r.testingFinishedOn_timestamp),
MONTH(r.testingFinishedOn_timestamp),
d.name
ORDER BY year, month;
A possible solution is to query data for the entire year and group by MONTH(testingFinishedOn_timestamp).
I added the query below but it's not tested:
SELECT
MONTH(r.testingFinishedOn_timestamp) ReleaseMonth,
COUNT(*) ReleasePerMonth,
d.name as DevGroup_REGION
FROM
release_summary r
inner join
gti_server_info g
on r.gti_server_id = g.gti_server_id
inner join
dev_group d
on d.dev_group_id = g.dev_group_id
WHERE
r.testingFinishedOn_timestamp >= '2020-01-01 00:00:00'
AND r.testingFinishedOn_timestamp < '2021-01-01 00:00:00'
AND r.test_type != 14
GROUP BY
d.name, MONTH(r.testingFinishedOn_timestamp);
ORDER BY
MONTH(r.testingFinishedOn_timestamp), d.name
Based on the documentation available, MONTH() function returns the number of the month, for instance for January returns 1.
If you want to have the name of the month you case use MONTHNAME() function instead of Month().
You can try the below query - using last_day()
SELECT year(r.testingFinishedOn_timestamp),month(r.testingFinishedOn_timestamp),
COUNT(*) ReleasePerMonth
FROM
release_summary r
inner join
gti_server_info g
on r.gti_server_id = g.gti_server_id
inner join
dev_group d
on d.dev_group_id = g.dev_group_id
WHERE
r.testingFinishedOn_timestamp >= date_add(date_add(LAST_DAY(now()),interval 1 DAY),interval -12 MONTH)
AND r.testingFinishedOn_timestamp <= LAST_DAY(now())
AND r.test_type != 14
GROUP BY
year(r.testingFinishedOn_timestamp),month(r.testingFinishedOn_timestamp) ;

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!

Better performance in MySQL subqueries for timeline graph

i have a query with subqueries for a timeline widget of participants, leads and customers.
For example with 15k rows in the table but only 2k in this date range (January 1st to January 28th) this takes about 40 seconds!
SELECT created_at as date,
(
SELECT COUNT(id)
FROM participant
WHERE created_at <= date
) as participants,
(
SELECT COUNT(DISTINCT id)
FROM participant
WHERE participant_type = "lead"
AND created_at <= date
) as leads,
(
SELECT COUNT(DISTINCT id)
FROM participant
WHERE participant_type = "customer"
AND created_at <= date
) as customer
FROM participant
WHERE created_at >= '2016-01-01 00:00:00'
AND created_at <= '2016-01-28 23:59:59'
GROUP BY date(date)
How can i improve the performance?
The table fields are declared as follows:
id => primary_key, INT 10, auto increment
participant_type => ENUM "lead,customer", NULLABLE, ut8_unicode_ci
created_at => TIMESTAMP, default '0000-00-00 00:00:00'
Possibly try using conditions within the counts (or sums) to get the values you want, having cross joined things:-
SELECT a.created_at as date,
SUM(IF(b.created_at <= a.created_at, 1, 0)) AS participants,
COUNT(DISTINCT IF(b.participant_type = "lead" AND b.created_at <= a.created_at, b.id, NULL)) AS leads,
COUNT(DISTINCT IF(b.participant_type = "customer" AND b.created_at <= a.created_at, b.id, NULL)) AS customer
FROM participant a
CROSS JOIN participant b
WHERE a.created_at >= '2016-01-01 00:00:00'
AND a.created_at <= '2016-01-28 23:59:59'
GROUP BY date(date)
or maybe move the date check into the join
SELECT a.created_at as date,
COUNT(b.id) AS participants,
COUNT(DISTINCT IF(b.participant_type = "lead", b.id, NULL)) AS leads,
COUNT(DISTINCT IF(b.participant_type = "customer", b.id, NULL)) AS customer
FROM participant a
LEFT OUTER JOIN participant b
ON b.created_at <= a.created_at
WHERE a.created_at >= '2016-01-01 00:00:00'
AND a.created_at <= '2016-01-28 23:59:59'
GROUP BY date(date)
I'm not clearly understanding what you want to do with this query. But may I can provide way for optimization.
Try this one:
SELECT
participants.day as day,
participants.total_count,
leads.lead_count,
customer.customer_count
FROM
(
SELECT created_at as day, COUNT(id) as total_count
FROM participant
WHERE created_at BETWEEN '2016-01-01 00:00:00' AND '2016-01-28 23:59:59'
GROUP BY day
) as participants
LEFT JOIN
(
SELECT created_at as day, COUNT(DISTINCT id) as lead_count
FROM participant
WHERE participant_type = "lead"
AND created_at BETWEEN '2016-01-01 00:00:00' AND '2016-01-28 23:59:59'
GROUP BY day
) as leads ON (participants.day = leads.day)
LEFT JOIN
(
SELECT created_at as day, COUNT(DISTINCT id) as customer_count
FROM participant
WHERE participant_type = "customer"
AND WHERE created_at BETWEEN '2016-01-01 00:00:00' AND '2016-01-28 23:59:59'
GROUP BY day
) as customer ON (participants.day = customer.day)
Add index to the query. You can execute Explain on this query.
With the help of EXPLAIN, you can see where you should add indexes to tables so that the statement executes faster by using indexes to find rows.

left join table and get date range per each table

i have the following query:
SELECT
t.aff_id,
Ifnull(t.campaign_name, "direct") AS campaign_name,
Count(t.uuid) AS visits,
Count(DISTINCT l.trader_id) AS leads
FROM trackings AS t
LEFT JOIN (SELECT uuid,
trader_id
FROM leads
WHERE aff_id = "1"
AND created_at BETWEEN "2015-05-01 00:00:00" AND
"2015-05-20 23:59:59") AS l
ON l.uuid = t.uuid
WHERE `t`.`created_at` BETWEEN '2015-05-01 00:00:00' AND '2015-05-20 23:59:59'
AND `t`.`aff_id` = '1'
GROUP BY `t`.`campaign_name`
the leads table date range has no effect, what should be the correct structure for such a query?
http://sqlfiddle.com/#!9/5d125/2
I think desired result can be reached with join:
SELECT
t.aff_id,
IFNULL(t.campaign_name, 'direct') AS campaign_name,
COUNT(t.uuid) AS visits,
COUNT(DISTINCT l.trader_id) AS leads
FROM trackings AS t
LEFT JOIN leads AS l
ON l.uuid = t.uuid
AND l.created_at BETWEEN '2015-05-01 00:00:00' AND '2015-05-20 23:59:59'
AND aff_id = '1'
WHERE
t.created_at BETWEEN '2015-05-01 00:00:00' AND '2015-05-20 23:59:59'
AND t.aff_id = '1'
GROUP BY
campaign_name
;