I'm newbie in MySQL and I have a table which has columns
+---------------------+-------------+
| Date | Temperature |
+---------------------+-------------+
| 2016-01-01 00:00:00 | 10,1 |
| 2016-01-02 00:00:00 | 10,2 |
| ... | ... |
| 2017-01-01 00:00:00 | 12,1 |
| 2017-01-02 00:00:00 | 12,5 |
+---------------------+-------------+
I would like receive the result
+--------+------+------+
| Date | 2016 | 2017 |
+--------+------+------+
| 01 Jan | 10,1 | 12,1 |
| 02 Jan | 10,2 | 12,5 |
| ... | ... | ... |
+--------+------+------+
I wanted to use subquery, but subquery can have 1 row. Someone could help me write the correct query?
use CASE statement
SELECT DATE_FORMAT(samay, '%e %b') AS date_month,
MAX(CASE WHEN EXTRACT(YEAR FROM samay) = 2016 THEN temp END) AS '2016',
MAX(CASE WHEN EXTRACT(YEAR FROM samay) = 2017 THEN temp END) AS '2017'
FROM date_test GROUP BY date_month;
You can try something like:
select d.fdate, t1.t, t2.t
from
(select distinct month(d) as month, day(d) as day, DATE_FORMAT(d, '%e %b') as fdate from h) as d
left outer join
(select DATE_FORMAT(d, '%e %b') as fdate, t from h where year(`d`) = 2016) as t1 on (d.fdate = t1.fdate)
left outer join
(select DATE_FORMAT(d, '%e %b') as fdate, t from h where year(`d`) = 2017) as t2 on (d.fdate = t2.fdate)
order by d.month, d.day
of course change column/table names
Demo http://www.sqlfiddle.com/#!9/920ea2/2
Related
In my Mysql database, I have 2 columns that store the start and end date of the process, respectively. I need to write a query that allows me to count the number of rows for each month in each column, and presents the count separately.
Table example:
+----+------------+----------------+
| id | startData | endData |
+----+-------------+----------------+
| 1 | 02/03/2020 | 02/03/2020 |
| 2 | 02/04/2020 | 02/04/2020 |
| 3 | 02/04/2020 | 02/05/2020 |
| 4 | 02/04/2020 | 02/05/2020 |
| 5 | 02/05/2020 | 02/06/2020 |
| 6 | 02/05/2020 | 02/06/2020 |
| 7 | 02/06/2020 | 02/07/2020 |
+----+-------------+----------------+
I want as a result:
+-------+--------------------+-------------------+
| month | count_month_start | count_month_end |
+-------+--------------------+-------------------+
| 03 | 01 | 01 |
| 04 | 03 | 01 |
| 05 | 02 | 02 |
| 06 | 01 | 02 |
| 07 | 00 | 01 |
+-------+--------------------+-------------------+
Assuming your start date and end date columns are of datatype date, you can do -
Select ifnull(Tb1.mn,Tb2.mn) As mn, ifnull(count_mn_start,0) As count_mn_start, ifnull(count_mn_end,0) As count_mn_end
from
(Select Month(StartDate) as mn, count(id) as count_mn_start
from
my_table
Group by Month(StartDate))Tb1
left Join (Select Month(EndDate) as mn, count(id) as count_mn_end
from my_table
Group by Month(EndDate)) Tb2
on Tb1.mn = Tb2.mn
UNION
Select ifnull(Tb1.mn,Tb2.mn) As mn, ifnull(count_mn_start,0) As count_mn_start, ifnull(count_mn_end,0) As count_mn_end
from
(Select Month(StartDate) as mn, count(id) as count_mn_start
from
my_table
Group by Month(StartDate))Tb1
Right Join (Select Month(EndDate) as mn, count(id) as count_mn_end
from my_table
Group by Month(EndDate)) Tb2
on Tb1.mn = Tb2.mn;
DB fiddle - https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=84ecddb9f5ed431ddff6a9eaab87e5df
PS : If your dates only have one year (2020 as your example) this would work, however ideally if you have different years in the data, consider having the year in the output as well and in that case use the same syntax ie Year(datefield) and add it in the select and group by in the sub-queries (same way as month in the above query).
A pretty simple way is to expand the time periods into days using a recursive CTE. Then just aggregate:
with recursive cte as (
select id, startdate as dte, enddate
from t
union all
select id, dte + interval 1 day, enddate
from cte
where dte < enddate
)
select year(dte), month(dte),
sum( day(dte) = 1 ) as cnt_start,
sum( day(dte) = day(last_day(dte)) ) as cnt_end
from cte
group by year(dte), month(dte) ;
Here is a db<>fiddle.
I am trying to create a MySQL query (MySQL v5) that totals call records by day/inbound number with a running cumulative total. I have referenced other pages on Stack Overflow but the results I'm getting are not adding up.
References:
MYSQL cumulative sum by date
MySQL cumulative sum order by date
The query looks like so:
SET #RUNNING_TOTAL :=0;
SELECT
DATE_FORMAT(start,'%d/%m/%Y') As CallDate,
ch.did AS InboundNo,
COUNT(*) AS DayTotal,
(#RUNNING_TOTAL := #RUNNING_TOTAL + COUNT(*)) AS CumulativeCalls
FROM
`call_history` ch
LEFT JOIN (SELECT callid, event FROM ast_queue_log WHERE event = 'ENTERQUEUE') aql ON aql.callid = ch.callid
WHERE
ch.did = '01234567891' AND
start BETWEEN DATE_FORMAT(NOW() ,'%Y-%m-01') AND NOW()
GROUP BY
ch.did, DATE(start)
ORDER BY
ch.did;
I would expect the following output:
+-------------------------------+-------------+----------+-----------------+
| CallDate | InboundNo | DayTotal | CumulativeCalls |
+-------------------------------+-------------+----------+-----------------+
| 01/05/2020 | 01234567891 | 232 | 232 |
| 02/05/2020 | 01234567891 | 50 | 282 |
| 03/05/2020 | 01234567891 | 14 | 296 |
| 04/05/2020 | 01234567891 | 246 | 542 |
| 05/05/2020 | 01234567891 | 187 | 729 |
| 06/05/2020 | 01234567891 | 182 | 911 |
| 07/05/2020 | 01234567891 | 105 | 1016 |
| 08/05/2020 | 01234567891 | 46 | 1062 |
| 09/05/2020 | 01234567891 | 26 | 1088 |
| 10/05/2020 | 01234567891 | 7 | 1095 |
| 11/05/2020 | 01234567891 | 255 | 1350 |
+-------------------------------+-------------+----------+-----------------+
What I am getting is the same values in DayTotal and CumulativeCalls for each day.
In MySQL 8+, you should be using window functions:
SELECT DATE_FORMAT(DATE(start), '%d/%m/%Y') As CallDate,
ch.did AS InboundNo,
COUNT(*) AS DayTotal,
SUM(COUNT(*)) OVER (PARTITION BY ch.did ORDER BY DATE(start)) as CumulativeCalls
FROM call_history ch LEFT JOIN
ast_queue_log aql
ON aql.event = 'ENTERQUEUE' AND aql.callid = ch.callid
WHERE ch.did = '01234567891' AND
start BETWEEN DATE_FORMAT(NOW(), '%Y-%m-01') AND NOW()
GROUP BY ch.did, DATE(start)
ORDER BY ch.did;
Notes:
The subquery is not needed for the LEFT JOIN.
All columns should be qualified. What table does start come from?
The GROUP BY and SELECT are consistent, by using DATE(start) in the SELECT statement.
In older versions of MySQL, you'll need variables and a subquery:
SELECT dc.*,
(#s := #s + DayTotal) as CumulativeCalls
FROM (SELECT DATE_FORMAT(DATE(start), '%d/%m/%Y') As CallDate,
ch.did AS InboundNo,
COUNT(*) AS DayTotal
FROM call_history ch LEFT JOIN
ast_queue_log aql
ON aql.event = 'ENTERQUEUE' AND aql.callid = ch.callid
WHERE ch.did = '01234567891' AND
start BETWEEN DATE_FORMAT(NOW(), '%Y-%m-01') AND NOW()
GROUP BY ch.did, DATE(start)
ORDER BY ch.did, DATE(start)
) dc CROSS JOIN
(SELECT #s := 0) params;
I have two working mysql select statements which I'd like to combine:
SELECT
t2.*,
t1.Lang,
Filmname,
ColFI
FROM Timetable t2, Contenttable t1
WHERE DATE_ADD(STR_TO_DATE(CONCAT('201825',' Thursday'), '%x%v %W'), INTERVAL 0 DAY) = DateSZ
AND RoomSZ =1 AND t2.idFI = t1.id
AND deleteSZ = false
ORDER BY TimeSZ
giving me (and of course some other irrelevant columns) for a specific day:
+----------+-------+------+------+------------+
| Filmname | time | idFI | Lang | DateSZ |
+----------+-------+------+------+------------+
| firstfi | 12:00 | 22 | eng | 2018-06-29 |
+----------+-------+------+------+------------+
| sencofi | 15:00 | 44 | fra | 2018-06-29 |
second:
SELECT
idFI,
COUNT(DISTINCT (case when Yweek < 201825 then Yweek end)) AS Week
FROM `Timetable`
GROUP BY idFI
giving me
+-------+------+
| Week | idFI |
+-------+------+
| 2 | 22 |
+-------+------+
| 1 | 44 |
My Timetable table is looking somewhat like this (plus some more columns):
+----------+-------+------+--------+------------+
| Filmname | time | idFI | Yweek | DateSZ |
+----------+-------+------+--------+------------+
| firstfi | 12:00 | 22 | 201825 | 2018-06-29 |
+----------+-------+------+--------+------------+
| firstfi | 18:00 | 22 | 201824 | 2018-06-21 |
+----------+-------+------+--------+------------+
| firstfi | 13:00 | 22 | 201823 | 2018-06-12 |
+----------+-------+------+--------+------------+
| sencofi | 15:00 | 44 | 201825 | 2018-06-29 |
+----------+-------+------+--------+------------+
| sencofi | 18:00 | 44 | 201823 | 2018-06-12 |
+----------+-------+------+--------+------------+
| sencofi | 10:00 | 44 | 201823 | 2018-06-13 |
My problem is, that if I insert the count(distinct) into the first select statement, it isn't working because it only counts rows witch meets all the where clauses in statement nr. 1. How can I combine these statements?
Edit:
Answer from #MKhalidJunaid, but not working with my formatting:
SELECT t2.*, t1.Lang, Filmname, ColFI, t3.Week DATE_FORMAT(DateSZ, '%d.%m.%y') AS DateSZ, TIME_FORMAT(TimeSZ, '%H:%i') AS TimeSZ
FROM Timetable t2
JOIN Contenttable t1 ON t2.idFI = t1.id
JOIN (
SELECT idFI, COUNT(DISTINCT (case when Yweek < 201825 then Yweek end)) AS Week
FROM Timetable
GROUP BY idFI
) t3 ON t2.idFI = t3.idFI
WHERE DATE_ADD(STR_TO_DATE(CONCAT('201825',' Thursday'), '%x%v %W'), INTERVAL 0 DAY) = DateSZ
AND RoomSZ =1
AND deleteSZ = false
ORDER BY TimeSZ
You could use a derived sub select for your count query and then join with your first query as
SELECT t2.*, t1.Lang, Filmname, ColFI , t3.Week
FROM Timetable t2
JOIN Contenttable t1 ON t2.idFI = t1.id
JOIN (
SELECT idFI, COUNT(DISTINCT (case when Yweek < 201825 then Yweek end)) AS Week
FROM Timetable
GROUP BY idFI
) t3 ON t2.idFI = t3.idFI
WHERE DATE_ADD(STR_TO_DATE(CONCAT('201825',' Thursday'), '%x%v %W'), INTERVAL 0 DAY) = DateSZ
AND RoomSZ =1
AND deleteSZ = false
ORDER BY TimeSZ
Also don't use old syntax for joining tables use explicit syntax using join keyword
Say we have the following tables, employee and payroll_slip:
Table: employee
id_employee | name_employee |
============|===============|
1 | john |
2 | doe |
3 | alex |
Table: payroll_slip
id_slip | id_employee | month_slip | year_slip |
========|=============|============|===========|
1 | 1 | 01 | 2016 |
2 | 2 | 01 | 2016 |
3 | 1 | 02 | 2016 |
4 | 2 | 02 | 2016 |
5 | 1 | 03 | 2016 |
6 | 3 | 03 | 2016 |
And we want to get the following result where month_slip = '03' AND year_slip = '2016'
id_employee | month_slip | year_slip | status_slip
============|============|===========|============
1 | 03 | 2016 | paid
2 | 03 | 2016 | unpaid
3 | 03 | 2016 | paid
I tried this query:
SELECT
a.id_employee,
payroll_slip.month_slip,
payroll_slip.year_slip,
IF(a.id_employee=payroll_slip.id_employee, 'paid', 'unpaid') AS status_slip
FROM (
SELECT id_employee FROM employee
UNION
SELECT id_employee FROM payroll_slip
) a
LEFT OUTER JOIN payroll_slip ON a.id_employee = payroll_slip.id_employee
LEFT OUTER JOIN employee ON a.id_employee = employee.id_employee
WHERE payroll_slip.month_slip = '03' AND payroll_slip.year_slip = '2016'
Any suggestion for this?
Try having a cross join:
SELECT X.id_employee, X.month_slip, X.year_slip
, CASE WHEN Y.id_employee IS NULL THEN 'Unpaid' ELSE 'Paid' END AS status_slip
FROM (
SELECT A.id_employee, B.month_slip, B.year_slip
from employee A
cross join (
select '03' AS month_slip, '2016' AS year_slip
) B
) X
LEFT JOIN payroll_slip Y
ON X.id_employee = Y.id_employee
AND X.month_slip = Y.month_slip
AND X.year_slip = Y.year_slip
Try this query:
SELECT e.id_employee, '03' AS month_slip, '2016' AS year_slip,
CASE WHEN p.id_employee IS NOT NULL THEN 'paid' ELSE 'unpaid' END AS status_slip
FROM employee e LEFT JOIN payroll_slip p
ON e.id_employee = p.id_employee AND p.month_slip = '03' AND p.year_slip = '2016'
The trick here is to move the restrictions on the month_slip and year_slip inside the JOIN condition, rather than in the WHERE clause.
Follow the link below for a running demo:
SQLFiddle
I have a table MeterReading in mysql and it has the following columns
meterid bigint(4),
reading bigint(4),
date date,
time time,
consumption,
primary key(meterid,reading)
i am inserting the vlues to this table except consumption and my problem is how to update the table based on these values.
i tried the following query
update MeterReading a
set consumption=(select reading-IFNULL((select MAX(reading) from MeterReading where meterid=a.meterid AND (date < a.date OR date = a.date AND time < a.time )),0));
i want the result like:
meterid | reading | date | time | consumption |
+---------+---------+------------+----------+-------------+
| 1 | 450 | 2012-10-05 | 06:05:05 | 450 |
| 1 | 550 | 2012-10-06 | 08:05:05 | 100 |
| 1 | 600 | 2012-10-07 | 09:05:05 | 50 |
| 1 | 700 | 2012-10-08 | 10:05:05 | 100 |
please help me
Try this instead:
UPDATE MeterReading a
LEFT JOIN
(
SELECT meterid, MAX(reading) MaxReading
FROM MeterReading
GROUP BY meterid
) g ON g.meterid = a.meterid
SET a.consumption = IFNULL(g.MaxReading, 0) - a.reading ;
Update: Use IFNULL(g.MaxReading, 0) - a.reading or you can use the ABS(IFNULL(g.MaxReading, 0) - a.reading).
SQL Fiddle Demo
Edit: So, you need to update each composite key (meterid, reading)'s consumption value with the difference between the current reading value and the next row's reading value. If so you can do this:
UPDATE MeterReading m
INNER JOIN
(
SELECT
m.*,
#rownum := #rownum + 1 AS rank
FROM meterreading m, (SELECT #rownum := 0) r
ORDER BY m.date
) t1 ON m.meterid = t1.meterid
AND m.reading = t1.reading
LEFT JOIN
(
SELECT
m.*,
#rownum2 := #rownum2 + 1 AS rank
FROM meterreading m, (SELECT #rownum2 := 0) r
ORDER BY m.date
) t2 ON t1.rank - t2.rank = 1
SET m.consumption = (t1.reading - IFNULL(t2.reading, 0));
Updated SQL Fiddle Demo
This will make your table meterreading, after update, looks like:
| METERID | READING | DATE | TIME | CONSUMPTION |
-----------------------------------------------------------------------------------------------------
| 1 | 450 | October, 05 2012 02:00:00+0000 | January, 01 1970 06:05:05+0000 | 450 |
| 1 | 550 | October, 06 2012 02:00:00+0000 | January, 01 1970 08:05:05+0000 | 100 |
| 1 | 600 | October, 07 2012 02:00:00+0000 | January, 01 1970 09:05:05+0000 | 50 |
| 1 | 700 | October, 08 2012 02:00:00+0000 | January, 01 1970 10:05:05+0000 | 100 |
Note that: I used the #rownum variable to get each row's rank, and the thing is, this rank is based on the order of the Date column, so it will get the next date's reading value.