MySQL return 0 if query is null - mysql

This query should select some statistic values form a table:
(SELECT MAX(`id`) as `count` FROM `stats` LIMIT 1)
UNION (SELECT COUNT(*) as `count` FROM `stats` WHERE DATE(`time`) >= (NOW() - INTERVAL 1 DAY) LIMIT 1)
UNION (SELECT COUNT(*) as `count` FROM `stats` WHERE DATE(`time`) >= (NOW() - INTERVAL 7 DAY) LIMIT 1)
UNION (SELECT COUNT(*) as `count` FROM `stats` WHERE DATE(`time`) >= (NOW() - INTERVAL 30 DAY) LIMIT 1)
UNION (SELECT DATE_FORMAT(MIN(`time`), '%D of %M, %Y') as `count` FROM `stats` LIMIT 1)
I tried this, but it doesn't work
(SELECT MAX(`id`) as `count` FROM `stats` LIMIT 1)
UNION IFNULL((SELECT COUNT(*) as `count` FROM `stats` WHERE DATE(`time`) >= (NOW() - INTERVAL 1 DAY) LIMIT 1), '0')
UNION IFNULL((SELECT COUNT(*) as `count` FROM `stats` WHERE DATE(`time`) >= (NOW() - INTERVAL 7 DAY) LIMIT 1), '0')
UNION IFNULL((SELECT COUNT(*) as `count` FROM `stats` WHERE DATE(`time`) >= (NOW() - INTERVAL 30 DAY) LIMIT 1), '0')
UNION IFNULL((SELECT DATE_FORMAT(MIN(`time`), '%D of %M, %Y') as `count` FROM `stats` LIMIT 1), '0')

You have to do SELECT on IFNULL:
SELECT MAX(`id`) as `count` FROM `stats` LIMIT 1
UNION
SELECT IFNULL((SELECT COUNT(*) as `count`
FROM `stats`
WHERE DATE(`time`) >= (NOW() - INTERVAL 1 DAY) LIMIT 1), 0)
UNION
SELECT IFNULL((SELECT COUNT(*) as `count`
FROM `stats`
WHERE DATE(`time`) >= (NOW() - INTERVAL 7 DAY) LIMIT 1), 0)
UNION
SELECT IFNULL((SELECT COUNT(*) as `count`
FROM `stats`
WHERE DATE(`time`) >= (NOW() - INTERVAL 30 DAY) LIMIT 1), 0)
UNION
SELECT IFNULL((SELECT DATE_FORMAT(MIN(`time`), '%D of %M, %Y') as `count`
FROM `stats` LIMIT 1), 0)
You also have to use 0 instead of '0' and get rid of the parentheses surrounding the first query.

Related

How to limit query results by a percentage of the total number of results in MySQL?

The below mysql question returns only the 10 first rows. How can I limit the them to 10% of all?
SELECT page,
poso,
diff
FROM (SELECT page,
Count(*) AS poso,
( Sum(Date(timestamp) = Curdate()) - Sum(
Date(timestamp) = Date_sub(Curdate(),
INTERVAL 1 day)) )
diff
FROM `behaviour`
WHERE Date(timestamp) >= Date_sub(Curdate(), INTERVAL 1 day)
GROUP BY page
ORDER BY ( Sum(Date(timestamp) = Curdate()) - Sum(
Date(timestamp) = Date_sub(Curdate(),
INTERVAL 1 day))
) DESC
LIMIT 10) AS u
ORDER BY diff DESC
Adapted from the answer to the duplicate question:
SELECT page,
poso,
diff
FROM (
SELECT *,
#counter := #counter + 1 AS counter
FROM (select #counter:=0) AS initvar,
(SELECT page,
Count(*) AS poso,
( Sum(Date(timestamp) = Curdate()) - Sum(
Date(timestamp) = Date_sub(Curdate(),
INTERVAL 1 day)) )
diff
FROM `behaviour`
WHERE Date(timestamp) >= Date_sub(Curdate(), INTERVAL 1 day)
GROUP BY page
ORDER BY ( Sum(Date(timestamp) = Curdate()) - Sum(
Date(timestamp) = Date_sub(Curdate(),
INTERVAL 1 day))
) DESC) AS u
) AS v
WHERE counter <= 10/100 * #counter
ORDER BY diff DESC;
Demo here: http://rextester.com/JKMBZR62923

MySQL UNION - Replicating a Sub Query

This is my current query:
Select Month as ReqMonth1,
sum(TotalUsage) As ReqCount1,
sum(Memberbase) as Club_updates_Records1,
round(sum(TotalUsage)/sum(Memberbase)*100,0) AS UsagePerc
from(
Select * from (
SELECT
CAST(DATE_FORMAT(Log_Date, '%b-%y') AS CHAR(100)) AS 'Month',
CAST(DATE_FORMAT(Log_Date, '%y-%m') AS CHAR(100)) AS 'Monthsort',
count(Requests.`fk_Members_ID`) AS TotalUsage,
0 as Memberbase
FROM
`Requests` Requests INNER JOIN `Members` Members ON Requests.`fk_Members_ID` = Members.`ID`
WHERE
cast(Requests.`Log_date` as date) BETWEEN date_sub(if($P{StartDate}>'2016-06-01',$P{StartDate},'2016-05-01'), Interval 4 month) and $P{EndDate} AND $P{EndDate}
AND Members.`Club` = $P{Club}
GROUP BY
CAST(DATE_FORMAT(Log_Date, '%M-%y') AS CHAR(100)) ) as A
UNION ALL
Select * from (
SELECT
CAST(DATE_FORMAT(Club_updates.`Update_Date`, '%b-%y') AS CHAR(100)) AS 'Month',
CAST(DATE_FORMAT(Club_updates.`Update_Date`, '%y-%m') AS CHAR(100)) AS 'Monthsort',
0 AS TotalUsage,
ifnull(max(Club_updates.`Records`),1) AS MemberBase
FROM
`Club updates` Club_updates
WHERE
cast(Club_updates.`Update_Date` as date) BETWEEN date_sub(if($P{StartDate}>'2016-06-01',$P{StartDate},'2016-05-01'), Interval 4 month) and $P{EndDate} AND $P{EndDate}
AND Club_updates.`fk_Club` = $P{Club}
GROUP BY CAST(DATE_FORMAT(Club_updates.`Update_Date`, '%M-%y') AS CHAR(100)) ) As B) as D
group by Month
Order by MonthSort
I'm trying to replicate/add another sub query "A" with the change on the Close_Date field instead of the Log_Date field in the WHERE clause.
Basically resulting a sum of both subqueries only in the "ReqCount1" field.
Any help would be appreciated.
Ok, got it solved
here's the solution(with an additional condition in the WHERE clause)
Select Month as ReqMonth1,
sum(TotalUsage) As ReqCount1,
sum(Memberbase) as Club_updates_Records1,
round(sum(TotalUsage)/sum(Memberbase)*100,0) AS UsagePerc
from(
Select * from (
SELECT
CAST(DATE_FORMAT(Log_Date, '%b-%y') AS CHAR(100)) AS 'Month',
CAST(DATE_FORMAT(Log_Date, '%y-%m') AS CHAR(100)) AS 'Monthsort',
count(Requests.`fk_Members_ID`) AS TotalUsage,
0 as Memberbase
FROM
`Requests` Requests INNER JOIN `Members` Members ON Requests.`fk_Members_ID` = Members.`ID`
WHERE
cast(Requests.`Log_date` as date) BETWEEN date_sub(if($P{StartDate}>'2016-06-01',$P{StartDate},'2016-05-01'), Interval 4 month) and $P{EndDate} AND $P{EndDate}
AND Members.`Club` = $P{Club} AND Requests.`Request_Type` <> 7
GROUP BY
CAST(DATE_FORMAT(Log_Date, '%M-%y') AS CHAR(100)) ) as A
UNION ALL
Select * from (
SELECT
CAST(DATE_FORMAT(Close_Date, '%b-%y') AS CHAR(100)) AS 'Month',
CAST(DATE_FORMAT(Close_Date, '%y-%m') AS CHAR(100)) AS 'Monthsort',
count(Requests.`fk_Members_ID`) AS TotalUsage,
0 as Memberbase
FROM
`Requests` Requests INNER JOIN `Members` Members ON Requests.`fk_Members_ID` = Members.`ID`
WHERE
cast(Requests.`Close_Date` as date) BETWEEN date_sub(if($P{StartDate}>'2016-06-01',$P{StartDate},'2016-05-01'), Interval 4 month) and $P{EndDate} AND $P{EndDate}
AND Members.`Club` = $P{Club} AND Requests.`Request_Type` = 7
GROUP BY
CAST(DATE_FORMAT(Close_Date, '%M-%y') AS CHAR(100)) ) as G
UNION ALL
Select * from (
SELECT
CAST(DATE_FORMAT(Club_updates.`Update_Date`, '%b-%y') AS CHAR(100)) AS 'Month',
CAST(DATE_FORMAT(Club_updates.`Update_Date`, '%y-%m') AS CHAR(100)) AS 'Monthsort',
0 AS TotalUsage,
ifnull(max(Club_updates.`Records`),1) AS MemberBase
FROM
`Club updates` Club_updates
WHERE
cast(Club_updates.`Update_Date` as date) BETWEEN date_sub(if($P{StartDate}>'2016-06-01',$P{StartDate},'2016-05-01'), Interval 4 month) and $P{EndDate} AND $P{EndDate}
AND Club_updates.`fk_Club` = $P{Club}
GROUP BY CAST(DATE_FORMAT(Club_updates.`Update_Date`, '%M-%y') AS CHAR(100)) ) As B) as D
group by Month
Order by MonthSort

MYSQL UNION GROUP BY

I'm doing this select statement:
SELECT * FROM (
SELECT COUNT(t.text) as count, COUNT(DISTINCT(t.from_user_id)) as usercount, DATE_FORMAT(t.created_at,'%Y-%m-%d %H:00') datepart
FROM TABLE1 t WHERE t.created_at >= '2015-08-12 00:00:00' AND t.created_at <= '2015-08-13 18:30:00' AND t.eliminar IS NULL
GROUP BY datepart) as t
UNION ALL
SELECT * FROM (
SELECT COUNT(b.id) as count, COUNT(DISTINCT(b.from_user_id)) as usercount, DATE_FORMAT(b.created_at,'%Y-%m-%d %H:00') datepart
FROM TABLE2 b WHERE b.created_at >= '2015-08-12 00:00:00' AND b.created_at <= '2015-08-13 18:30:00' AND b.eliminar IS NULL
GROUP BY datepart) as x GROUP BY datepart
this select gets this:
I'm trying to view with datepart grouped but I can't, any idea what I'm doing wrong?
TABLE2 only have (id,from_user_id,eliminar) and all are NULL except created_at, in this row I have entire 2015 year by day and hour, same format as TABLE1
SOLVED:
SELECT DISTINCT * FROM (
SELECT COUNT(t.text) as count, COUNT(DISTINCT(t.from_user_id)) as usercount, DATE_FORMAT(t.created_at,'%Y-%m-%d %H:00') datepart
FROM TABLE1 t WHERE t.created_at >= '2015-08-12 00:00:00' AND t.created_at <= '2015-08-13 18:30:00' AND t.eliminar IS NULL
GROUP BY datepart
UNION ALL
SELECT COUNT(t.id) as count, COUNT(DISTINCT(t.from_user_id)) as usercount, DATE_FORMAT(t.created_at,'%Y-%m-%d %H:00') datepart
FROM TABLE2 t WHERE t.created_at >= '2015-08-12 00:00:00' AND t.created_at <= '2015-08-13 18:30:00' AND t.eliminar IS NULL
GROUP BY datepart) as x GROUP BY datepart ORDER BY datepart

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

multiple MySQL queries to a single insert

I'm trying to perform a number of MySQL queries and to write the results as a single line to a different database and table.
So this works
INSERT INTO bridgedb.stats (longestcall, totalmins, totalconfs)
SELECT
(SELECT MAX(duration) AS longestcall FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY),
(SELECT SUM(duration) AS totalmins FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY),
(SELECT COUNT(*) FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY);
and this works
INSERT INTO bridgedb.stats (date, peakchan)
SELECT
`calldate`,
MAX(concurrent)+1 AS peakcount
FROM (
SELECT
DATE(a.calldate) as calldate,
COUNT(b.uniqueid) AS concurrent
FROM asteriskcdr.cdr AS a, asteriskcdr.cdr AS b
WHERE
a.calldate >= NOW() - INTERVAL 4 DAY
AND (
(a.calldate<=b.calldate AND (UNIX_TIMESTAMP(a.calldate)+a.duration)>=UNIX_TIMESTAMP(b.calldate))
OR (b.calldate<=a.calldate AND (UNIX_TIMESTAMP(b.calldate)+b.duration)>=UNIX_TIMESTAMP(a.calldate))
)
AND a.uniqueid>b.uniqueid
GROUP BY a.uniqueid
) AS baseview
GROUP BY calldate;
But this doesn't work
INSERT INTO bridgedb.stats (date, peakchan, longestcall, totalmins, totalconfs)
SELECT
(SELECT
`calldate`,
MAX(concurrent)+1 AS peakcount
FROM (
SELECT
DATE(a.calldate) as calldate,
COUNT(b.uniqueid) AS concurrent
FROM asteriskcdr.cdr AS a, asteriskcdr.cdr AS b
WHERE
a.calldate >= NOW() - INTERVAL 1 DAY
AND (
(a.calldate<=b.calldate AND (UNIX_TIMESTAMP(a.calldate)+a.duration)>=UNIX_TIMESTAMP(b.calldate))
OR (b.calldate<=a.calldate AND (UNIX_TIMESTAMP(b.calldate)+b.duration)>=UNIX_TIMESTAMP(a.calldate))
)
AND a.uniqueid>b.uniqueid
GROUP BY a.uniqueid
) AS baseview
GROUP BY calldate),
(SELECT MAX(duration) AS longestcall FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY),
(SELECT SUM(duration) AS totalmins FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY),
(SELECT COUNT(*) FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY);
I get an error #1241 - Operand should contain 1 column(s)
Does anyone know how I can make this work for all the queries?
Try using session variables or abstract it away into a stored procedure, something like -
First:
SELECT
#calldate:=`calldate`,
#peakchan:=MAX(concurrent)+1
FROM (
...
) AS baseview
GROUP BY calldate
Second:
SELECT #longestcall:=MAX(duration) FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY
Third:
SELECT #totalmins:=SUM(duration) FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY
Fourth:
SELECT #totalconfs:=COUNT(*) FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY;
And finally
INSERT INTO bridgedb.stats (date, peakchan, longestcall, totalmins, totalconfs)
VALUES (#calldate, #peakchan, #longestcall, #totalmins, #totalconfs)
BTW: It is not a good idea to call a column date.
EDIT
Ofcourse you need to make sure, those queries run in the same session to use session variables. This is the default when run with a single DB connection in PHP
EDIT 2
To handle periods without activity, you can
either prefix this with SELECT #calldate:=DATE(NOW() - INTERVAL 1 DAY), #peakchan:=0, #longestcall:=0, #totalmins:=0, #totalconfs:=0; (record with defaults created)
or stop after the first query, if #calldate is NULL (no record created)
EDIT 3
This works for me:
DELIMITER //
CREATE PROCEDURE ReportYesterday()
BEGIN
DECLARE calldate DATE;
DECLARE peakchan, longestcall, totalmins, totalconfs INT;
SELECT
#calldate:=`calldate`,
#peakchan:=MAX(concurrent)+1
FROM (
SELECT
DATE(a.calldate) as calldate,
COUNT(b.uniqueid) AS concurrent
FROM asteriskcdr.cdr AS a, asteriskcdr.cdr AS b
WHERE
a.calldate >= NOW() - INTERVAL 1 DAY
AND (
(a.calldate<=b.calldate AND (UNIX_TIMESTAMP(a.calldate)+a.duration)>=UNIX_TIMESTAMP(b.calldate))
OR (b.calldate<=a.calldate AND (UNIX_TIMESTAMP(b.calldate)+b.duration)>=UNIX_TIMESTAMP(a.calldate))
)
AND a.uniqueid>b.uniqueid
GROUP BY a.uniqueid) AS baseview
GROUP BY calldate
;
-- EDIT 4 IS THE FOLLOWING LINE
IF #calldate IS NOT NULL THEN
SELECT #longestcall:=MAX(duration) FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY
;
SELECT #totalmins:=SUM(duration) FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY
;
SELECT #totalconfs:=COUNT(*) FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY
;
INSERT INTO bridgedb.stats (date, peakchan, longestcall, totalmins, totalconfs)
VALUES (#calldate, #peakchan, #longestcall, #totalmins, #totalconfs)
;
END IF;
END
;
//
DELIMITER ;
followed by
CALL ReportYesterday();
You must build a (valid) SELECT query which returns all rows. Your former SELECT was not valid. This one should work:
INSERT INTO bridgedb.stats (date, peakchan, longestcall, totalmins, totalconfs)
SELECT
`calldate`,
MAX(concurrent)+1 AS peakcount,
(SELECT MAX(duration) AS longestcall FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY),
(SELECT SUM(duration) AS totalmins FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY),
(SELECT COUNT(*) FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY)
FROM (
SELECT
DATE(a.calldate) as calldate,
COUNT(b.uniqueid) AS concurrent
FROM asteriskcdr.cdr AS a, asteriskcdr.cdr AS b
WHERE
a.calldate >= NOW() - INTERVAL 1 DAY
AND (
(a.calldate<=b.calldate AND (UNIX_TIMESTAMP(a.calldate)+a.duration)>=UNIX_TIMESTAMP(b.calldate))
OR (b.calldate<=a.calldate AND (UNIX_TIMESTAMP(b.calldate)+b.duration)>=UNIX_TIMESTAMP(a.calldate))
)
AND a.uniqueid>b.uniqueid
GROUP BY a.uniqueid
) AS baseview
GROUP BY calldate;