Query for Count on coulmns by condition with Group BY - mysql

Table structure
id(int)
dated_on(datetime)
(many_more)
Table having thousands of data grouped by id.
I want result as id, count of that id,
also count of id having date difference is week.(i.e. count of data last week)

select
id,
count(id) as cnt,
sum(if(now() - interval 7 day <= dated_on,1,0)) as lastweek
from table
group by id

SELECT
id,
COUNT(*),
SUM(CASE WHEN dated_on = CURDATE() - 7 THEN 1 ELSE 0 END)
FROM
yourTable
GROUP BY
id

I also got solution:
SELECT id, count(id) as counter,
COUNT(CASE WHEN DATEDIFF( CURDATE(), dated_on ) < 7 THEN 1 ELSE NULL END) AS latest_count
FROM my_table
GROUP BY id

Related

How ot return 0 instead of null on mysql query?

The following query returns the visitors and pageviews of last 7 days. However, if there are no results (let's say it is a fresh account), nothing is returned.
How to edit this in order to return 0 in days that there are no entries?
SELECT Date(timestamp) AS day,
Count(DISTINCT hash) AS visitors,
Count(*) AS pageviews
FROM behaviour
WHERE company_id = 1
AND timestamp >= Subdate(Curdate(), 7)
GROUP BY day
Assuming that you always have at least one record in the table for each of the last 7 days (regardless of the company_id), then you can use conditional aggregation as follows:
select
date(timestamp) as day,
count(distinct case when company_id = 1 then hash end) as visitors,
sum(company_id = 1) as pageviews
from behaviour
where timestamp >= curdate() - interval 7 day
group by day
Note that I changed you query to use standard date arithmetics, which I find easier to understand that date functions.
Otherwise, you would need to move the condition on the date from the where clause to the aggregate functions:
select
date(timestamp) as day,
count(distinct case when timestamp >= curdate() - interval 7 day and company_id = 1 then hash end) as visitors,
sum(timestamp >= curdate() - interval 7 day and company_id = 1) as pageviews
from behaviour
group by day
If your table is big, this can be expensive so I would not recommend that.
Alternatively, you can generate a derived table of dates and left join it with your original query:
select
curdate - interval x.n day day,
count(distinct b.hash) visitors,
count(b.hash) page_views
from (
select 1 n union all select 2 union all select 3 union all select 4
union all select 5 union all select 6 union all select 7
) x
left join behavior b
on b.company_id = 1
and b.timestamp >= curdate() - interval x.n day
and b.timestamp < curdate() - interval (x.n - 1) day
group by x.n
Use a query that returns all the dates from today minus 7 days to today and left join the table behaviour:
SELECT t.timestamp AS day,
Count(DISTINCT b.hash) AS visitors,
Count(b.timestamp) AS pageviews
FROM (
SELECT Subdate(Curdate(), 7) timestamp UNION ALL SELECT Subdate(Curdate(), 6) UNION ALL
SELECT Subdate(Curdate(), 5) UNION ALL SELECT Subdate(Curdate(), 4) UNION ALL SELECT Subdate(Curdate(), 3) UNION ALL
SELECT Subdate(Curdate(), 2) UNION ALL SELECT Subdate(Curdate(), 1) UNION ALL SELECT Curdate()
) t LEFT JOIN behaviour b
ON Date(b.timestamp) = t.timestamp AND b.company_id = 1
GROUP BY day
Use IFNULL:
IFNULL(expr1, 0)
From the documentation:
If expr1 is not NULL, IFNULL() returns expr1; otherwise it returns expr2. IFNULL() returns >a numeric or string value, depending on the context in which it is used.
You can use next trick:
First, get query that return 1 dummy row: SELECT 1;
Next use LEFT JOIN to connect summary row(s) without condition. This join will return values in case data exists on NULL values in other case.
Last select from joined queries onle what we need and convert NULL's to ZERO's
using IFNULL dunction.
SELECT
IFNULL(b.day,0) AS DAY,
IFNULL(b.visitors,0) AS visitors,
IFNULL(b.pageviews,0) AS pageviews
FROM (
SELECT 1
) a
LEFT JOIN (
SELECT DATE(TIMESTAMP) AS DAY,
COUNT(DISTINCT HASH) AS visitors,
COUNT(*) AS pageviews
FROM behaviour
WHERE company_id = 1
AND TIMESTAMP >= SUBDATE(CURDATE(), 7)
GROUP BY DAY
) b ON 1 = 1;

Count rows having status "closed" and status "unclosed" for every month in a year

This is the table, I need to get count of rows for status cloesd and status unclosed for every month in a year. Thanks in advance.
The table image
You can try following query.
SELECT *
FROM
(
(
SELECT MONTH(mt1.calltime) AS MONTH, YEAR(mt1.`calltime`) AS YEAR, COUNT(mt1.`status`) AS closed, 0 AS unclosed
FROM myTable mt1
WHERE mt1.`status`='closed'
)
UNION ALL
(
SELECT MONTH(mt2.calltime) AS MONTH, YEAR(mt2.`calltime`) AS YEAR, 0 AS closed, COUNT(mt2.`status`) AS unclosed
FROM myTable mt2
WHERE mt2.`status`='unclosed'
)
) AS tablea
GROUP BY tablea.month
Replace myTable with your tablename.
MONTH will extract month of the year from the given date, and YEAR will give year.
SQL FIDDLE
select count(*) from table1
where status in ('closed,unclosed')
group by status,month(call_time)
Try this:
SELECT COUNT(*) FROM <table name> WHERE status="closed";
SELECT COUNT(*) FROM <table name> WHERE status="unclosed";
Get year part from the date using YEAR and month part using MONTH functions and status column from the table and use this as a subset and then use CASE expression to count the Closed and Unclosed status group by the year and month.
Query
SELECT t.`YEAR`, t.`MONTH`,
SUM(CASE t.`status` WHEN 'Closed' THEN 1 ELSE 0 END) AS `Closed`,
SUM(CASE t.`status` WHEN 'Unclosed' THEN 1 ELSE 0 END) AS `UnClosed`
FROM(
SELECT YEAR(`call_time`) AS `YEAR`,
MONTH(`call_time`) AS `MONTH`,
`status`
FROM `your_table_name`
)t
GROUP BY t.`YEAR`, t.`MONTH`;
SQL Fiddle demo

MYSQL get total sum and sum between 2 date in 1 query

I am trying to get the total sum of a column and the sum of the same column between 2 dates in one query. is this possible?
My table looks like this:
uid|amount|date
The two queries i am trying to make one of:
SELECT sum(amount) as `keys` FROM tbl_keys WHERE uid = 1
SELECT sum(amount) as `keys` FROM tbl_keys WHERE uid = 1 AND YEAR(`date`) = YEAR(CURRENT_DATE)
AND MONTH(`date`) = MONTH(CURRENT_DATE)
You could use a UNION query:
SELECT 'All' AS cnt, sum(amount) as `keys` FROM tbl_keys WHERE uid = 1
UNION ALL
SELECT 'Current_month' AS cnt, sum(amount) as `keys`
FROM tbl_keys
WHERE
uid = 1
AND `date`<= last_day(current_date)
`date`>= current_date - interval (day(current_date)-1) day
(I prefer to use >= and <= on the date column, as it can make use of an index if present, while functions like MONTH() or YEAR() cannot, also I assume that date is a date columnd and that it doesn't contain time informations).
If you want the result in one row, you could use an inline query:
SELECT
(SELECT sum(amount) as `keys` FROM tbl_keys WHERE uid = 1) AS total,
(SELECT sum(amount) as `keys`
FROM tbl_keys
WHERE
uid = 1
AND `date`<= last_day(current_date)
`date`>= current_date - interval (day(current_date)-1) day
) AS current_month
Something like this:
SELECT sum(amount) as `keys`,
(
SELECT sum(t.amount)
FROM tbl_keys as t
WHERE t.uid = tbl_keys.uid AND YEAR(t.`date`) = YEAR(CURRENT_DATE)
AND MONTH(t.`date`) = MONTH(CURRENT_DATE)
) as `keys2`
FROM tbl_keys
WHERE uid = 1
SELECT sum(amount) AS `keys`
FROM (
SELECT amount FROM tbl_keys
UNION ALL
SELECT amount FROM tbl_keys
WHERE uid = 1
AND YEAR(`date`) = YEAR(CURRENT_DATE)
AND MONTH(`date`) = MONTH(CURRENT_DATE)
) AS new_table;
Using a UNION clause, you will get the desired output you want.
Use CASE to count only the amount for the specified date:
SELECT SUM(amount) AS `keys`,
SUM(CASE WHEN YEAR(`date`) = YEAR(CURRENT_DATE)
AND MONTH(`date`) = MONTH(CURRENT_DATE) THEN amount ELSE 0 END) AS 'keys2'
FROM tbl_keys
WHERE uid = 1
;
My guess is that this will run more efficient than a solution using UNION SELECT.

First and last record for a user in a given time period in one query

I am looking to get the first and last record for a given user_id in a time period, for example, 24 hours.
I am aware this could be done using two queries, doing something like this and then switching the ORDER BY ASC/DESC.
SELECT id, user_id, date, other_columns
FROM table
WHERE user_id = 1 AND date > DATE_SUB(CURDATE(), INTERVAL 24 HOUR)
ORDER BY date DESC
LIMIT 1
However, I am wondering if it would be possible to do this using one query.
This is something that you could consider:
SELECT t.id, t.user_id, t.date, t.other_columns
FROM table t
WHERE user_id = 1
AND date = (
SELECT MIN(date)
FROM table
WHERE user_id = t.user_id
AND date > DATE_SUB(CURDATE(), INTERVAL 24 HOUR))
UNION ALL
SELECT id, user_id, date, other_columns
FROM table
WHERE user_id = 1
AND date = (
SELECT MAX(date)
FROM table
WHERE user_id = t.user_id
AND date > DATE_SUB(CURDATE(), INTERVAL 24 HOUR))

specific status on consecutive days

I have a MySQL table ATT which has EMP_ID,ATT_DATE,ATT_STATUS with ATT_STATUS with different values 1-Present,2-Absent,3-Weekly-off. I want to find out those EMP_ID's which have status 2 consecutively for 10 days in a given date range.
Please help
Please have a try with this:
SELECT EMP_ID FROM (
SELECT
IF((#prevDate!=(q.ATT_DATE - INTERVAL 1 DAY)) OR (#prevEmp!=q.EMP_ID) OR (q.ATT_STATUS != 2), #rownum:=#rownum+1, #rownum:=#rownum) AS rownumber, #prevDate:=q.ATT_DATE, #prevEmp:=q.EMP_ID, q.*
FROM (
SELECT
EMP_ID
, ATT_DATE
, ATT_STATUS
FROM
org_tb_dailyattendance, (SELECT #rownum:=0, #prevDate:='', #prevEmp:=0) vars
WHERE ATT_DATE BETWEEN '2013-01-01' AND '2013-02-15'
ORDER BY EMP_ID, ATT_DATE, ATT_STATUS
) q
) sq
GROUP BY EMP_ID, rownumber
HAVING COUNT(*) >= 10
The logic is, to first sort the table by employee id and the dates. Then introduce a rownumber which increases only if
the days are not consecutive or
the employee id is not the previous one or
the status is not 2
Then I just grouped by this rownumber and counted if there are 10 rows in each group. That should be the ones who were absent for 10 days or more.
Have you tried something like this
SELECT EMP_ID count(*) as consecutive_count min(ATT_DATE)
FROM (SELECT * FROM ATT ORDER BY EMP_ID)
GROUP BY EMP_ID, ATT_DATE
WHERE ATT_STATUS = 2
HAVING consecutive_count > 10