mysql arithmetik operation (subtraction) last - first of the day(week, month) - mysql

i got a MySQL tbl, with some colums, where every 5 min. a new row is inserted with 3 values
1. Auto inc. curent Date Unix timestamp --> date
2. power consumption absolut --> wert01
3. Power Generation absolut --> wert02
To Show this Information in a Graph, for Exampl for weekly power consumption, i need to select the First and the last, which allready Works, but then have to Substract the last from the First and Show only tue result & the day of the werk.
SELECT
(SELECT wert01
FROM sml_splitt
WHERE date >= curdate() - INTERVAL DAYOFWEEK(curdate())+6 DAY
AND date < curdate() - INTERVAL DAYOFWEEK(curdate()) DAY
ORDER BY date DESC LIMIT 1) AS 'last',
(SELECT wert01
FROM sml_splitt
WHERE date >= curdate() - INTERVAL DAYOFWEEK(curdate())+6 DAY
AND date < curdate() - INTERVAL DAYOFWEEK(curdate()) DAY
ORDER BY date LIMIT 1) AS 'lirst
I am searching for some days to find a solution, but with no success.
Hopfuly, you could help me.

If you're happy with your query, then you can do the math by nesting it one more time like this: http://sqlfiddle.com/#!9/515ef/1
select t1.last, t1.first, t1.last - t1.first as result
from (
select (
select wert01
from sml_splitt
where dt >= curdate() - interval dayofweek(curdate()) + 6 day
and dt < curdate() - interval dayofweek(curdate()) day
order by dt desc limit 1
) as 'last',
(
select wert01
from sml_splitt
where dt >= curdate() - interval dayofweek(curdate()) + 6 day
and dt < curdate() - interval dayofweek(curdate()) day
order by dt limit 1
) as 'first'
) t1
;
If you really want to work with this data by week for reporting purposes, let me suggest a couple of views. The first will give you all of your distinct beginning of week dates:
create view v1 as
select date(dt) as week_begins
from sml_splitt
where dayofweek(dt) = 1
group by week_begins
The second view joins the first view with itself to give you a week beginning and week ending range:
create view v2 as
select t1.week_begins, coalesce(t2.week_begins,now()) as week_ends
from v1 t1
left join v1 t2
on t2.week_begins = t1.week_begins + interval 7 day
You can see the results here: http://sqlfiddle.com/#!9/a4d1b3/2. Notice that I'm using now() to get the current date and time if the week hasn't ended yet.
From there you can join your view with your original table and use min() and max() function with grouping to get the starting and ending 'wert' values and do any calculations on them that you like.
Here's an example: http://sqlfiddle.com/#!9/a4d1b3/6
select week_begins, week_ends,
min(wert01) as start_wert01,
max(wert01) as end_wert01,
max(wert01) - min(wert01) as power_consumed,
min(wert02) as start_wert02,
max(wert02) as end_wert02,
max(wert02) - min(wert02) as power_generated,
(max(wert02) - min(wert02)) - (max(wert01) - min(wert01)) as net_generated
from v2
inner join sml_splitt
on sml_splitt.dt >= v2.week_begins
and sml_splitt.dt < v2.week_ends
group by week_begins
I hope that helps.

Related

MySQL - How to find records for yesterday when timestamp is part of date

My MySQL table stores records with a date/time stamp. I am wanting to find records from the table that were created yesterday (as in have a creation date of yesterday - regardless of what the timestamp portion is)
Below is what a db record looks like:
I have tried the following select (and a few other variations, but am not getting the rows with yesterday's date.
SELECT m.meeting_id, m.member_id, m.org_id, m.title
FROM meeting m
WHERE m.create_dtm = DATE_SUB(CURDATE(), INTERVAL 1 DAY)
Not exactly sure how I need to structure the where clause to get meeting ids that occurred yesterday. Any help would be greatly appreciated.
A naive approach would truncate the creation timestamp to date, then compare:
where date(m.create_dtm) = current_date - interval 1 day
But it is far more efficient to use half-open interval directly against the timestamp:
where m.create_dtm >= current_date - interval 1 day and m.create_dtm < current_date
You can try next queries:
SELECT
m.meeting_id, m.member_id, m.org_id, m.title, m.create_dtm
FROM meeting m
-- here we convert datetime to date for each row
-- it can be expensive for big table
WHERE date(create_dtm) = DATE_SUB(CURDATE(), INTERVAL 1 DAY);
SELECT
m.meeting_id, m.member_id, m.org_id, m.title, m.create_dtm
FROM meeting m
-- here we calculate border values once and use them
WHERE create_dtm BETWEEN DATE_SUB(CURDATE(), INTERVAL 1 DAY) AND DATE_SUB(CURDATE(), INTERVAL 1 SECOND);
Here live fiddle: SQLize.online

Introducing a new column for previous month sum

I am trying to introduce a new column for my query, it currently counts sum of expenses in this month, the new column should display last months expences. I am not quite sure where to place it.
SELECT cat.id_kat,
cat.nazwa,
coalesce(exp.tot, 0) AS PriceTotal
FROM wydatki_kategorie cat
LEFT JOIN
(SELECT wydatki_wpisy.kategoria,
sum(wydatki_wpisy.brutto) AS tot
FROM wydatki_wpisy
LEFT JOIN wydatki ON wydatki_wpisy.do_wydatku = wydatki.id_wydatku
WHERE MONTH(wydatki.data_zakupu) = MONTH(CURRENT_DATE())
AND wydatki.id_kupujacy = 1
GROUP BY wydatki_wpisy.kategoria) exp ON cat.id_kat = exp.kategoria
Possibly might be needed ( if I'm not wrong ) - Where clause for the previous month.
wydatki.data_zakupu >= DATE_ADD(LAST_DAY(DATE_SUB(NOW(), INTERVAL 2 MONTH)), INTERVAL 1 DAY) AND
wydatki.data_zakupu<= DATE_SUB(NOW(), INTERVAL 1 MONTH)
SQL Fiddle example
Two things.
First, if you stop using WHERE MONTH(wydatki.data_zakupu) = MONTH(CURRENT_DATE()) to choose your dates you'll get three benefits.
Your date searching will become sargable: an index will speed it up.
You'll get a more general scheme for choosing months.
If you have multiple years' worth of data in your tables, things will work better.
Instead, in general use this sort of expression to search for the present month. You already figured out most of this.
WHERE wydatki.data_zakupu >= LAST_DAY(CURRENT_DATE()) + INTERVAL 1 DAY - INTERVAL 1 MONTH
AND wydatki.data_zakupu < LAST_DAY(CURRENT_DATE()) + INTERVAL 1 DAY - INTERVAL 0 MONTH
This looks for all datetime values on or after midnight at the first day of the present month, and before, but not on <, midnight at the first day of next month.
It generalizes to any month you want. For example,
WHERE wydatki.data_zakupu >= LAST_DAY(CURRENT_DATE()) + INTERVAL 1 DAY - INTERVAL 2 MONTH
AND wydatki.data_zakupu < LAST_DAY(CURRENT_DATE()) + INTERVAL 1 DAY - INTERVAL 1 MONTH
gets you last month. This also works when the current month is January, and it works when you have multiple years' worth of data in your tables.
These expressions are a little verbose because MySQL doesn't have a FIRST_DAY(date) function, only a LAST_DAY(date) function. So we need all that + INTERVAL 1 DAY monkey business.
Second, pulling out a previous month's data is as simple as adding another LEFT JOIN ( SELECT... clause to your table, like so. (http://sqlfiddle.com/#!9/676df4/13)
SELECT ...
coalesce(month1.tot, 0) AS LastMonth
FROM wydatki_kategorie cat
LEFT JOIN
...
LEFT JOIN
(SELECT wydatki_wpisy.kategoria,
sum(wydatki_wpisy.brutto) AS tot
FROM wydatki_wpisy
LEFT JOIN wydatki ON wydatki_wpisy.do_wydatku = wydatki.id_wydatku
WHERE wydatki.data_zakupu >= LAST_DAY(CURRENT_DATE()) + INTERVAL 1 DAY - INTERVAL 2 MONTH
AND wydatki.data_zakupu < LAST_DAY(CURRENT_DATE()) + INTERVAL 1 DAY - INTERVAL 1 MONTH
AND wydatki.id_kupujacy = 1
GROUP BY wydatki_wpisy.kategoria
) month1 ON cat.id_kat = month1.kategoria
As you can see, the date range WHERE clause here gets the previous month's rows.

How do I subtract two results from a SELECT statement within that statement?

This pulls back two int values of yesterday and today. I'd like to subtract the two results from within the statement in a third column called difference:
SELECT (
SELECT COUNT(*)
FROM collectors_users
WHERE DATE(dateadded) = CURDATE() - INTERVAL 1 DAY
) AS yesterday, COUNT(*) AS today
FROM collectors_users
WHERE DATE(dateadded) = CURDATE()
You need to repeat the expressions. SQL (in general) does not allow you to re-use column aliases in the same SELECT. You can simplify the logic to:
SELECT SUM(DATE(dateadded) = CURDATE() - INTERVAL 1 DAY) AS yesterday,
SUM(DATE(dateadded) = CURDATE()) as today,
(SUM(DATE(dateadded) = CURDATE()) -
SUM(DATE(dateadded) = CURDATE() - INTERVAL 1 DAY)
) as diff
FROM collectors_users
WHERE dateadded >= CURDATE() - INTERVAL 1 DAY AND
dateadded < CURDATE() + INTERVAL 1 DAY;
Note that the logic for the WHERE clause covers two days. Also, it does not use DATE(). This would allow the query to use an index, if available.

How do I find all data from a table in a specific month

I am trying to retrieve all data from table in a specific month, my date format in the database table is 2016-06-19 I am need to find with the respect of a selected date, like if I select 2016-05-22
it will retrieve 2016-05-07 to 2016-06-06 interval values from the table.
And also to all the values in this month which is 05 month, I am using mysqli with PHP. I have tried using this query
SELECT * FROM t_tenancy_details WHERE
agreement_date >= DATE_FORMAT( CURRENT_DATE - INTERVAL 1 MONTH, '%Y/%m/01' )AND
agreement_date < DATE_FORMAT( CURRENT_DATE, '%Y/%m/01' )
This works fine for the running month, But problem is that if I select a previous month it does not work.
It's not very clear from the question as to what is needed. Based on the 2 requirements that I could understand:
Get everything surrounding the given date (i.e. +-15 days from the given date):
SELECT *
FROM t_tenancy_details
WHERE agreement_date >= DATE_SUB(#d, INTERVAL 15 DAY)
AND agreement_date <= DATE_ADD(#d, INTERVAL 15 DAY);
Get all the records where the month is same as the month in the given date:
SELECT *
FROM t_tenancy_details
WHERE MONTH(agreement_date) = MONTH(#d)
AND YEAR(agreement_date) = YEAR(#d);
where #d is the input date, in your case - CURRENT_DATE
Should be this
SELECT * FROM t_tenancy_details
WHERE (YEAR(t_tenancy_details) => YEAR(CURRENT_DATE - INTERVAL 1 MONTH)
AND MONTH(agreement_date) => MONTH(CURRENT_DATE - INTERVAL 1 MONTH))
AND (YEAR(t_tenancy_details) <= YEAR(CURRENT_DATE)
AND MONTH(agreement_date) <= MONTH(CURRENT_DATE))

MySQL: search orders made since yesterday 3pm till today 4pm

I have table ORDERS where is stored data about orders with their status and the date of order. I would like to search all orders with specified status and which was made yesterday after 3pm untill today 4pm. The query will run in different times (10am, 3pm, 5 pm... regardless).
So on example: if I run the query today (13.05.2014) I would like to get all orders made from 2014-12-05 15:00:00 untill 13-05-2015 16:00:00
The date is stored in format: YYYY-MM-DD HH:MM:SS
What I got is:
select *
from orders
where status = 'new'
and (
(
date_add(created_at, INTERVAL 1 day) = CURRENT_DATE()
and hour(created_at) >= 15
) /*1*/
or (
date(created_at) = CURRENT_DATE()
and hour(created_at) <= 16
) /*2*/
)
And I get only orders made today - like only the 2nd condition was taken into account.
I prefer not to use created >= '2014-05-12 16:00:00' (I will not use this query, someone else will).
When you add an interval of 1 day to the date/time, you still keep the time component. Use date() for the first condition:
where status = 'new' and
((date(date_add(created_at, INTERVAL 1 day)) = CURRENT_DATE() and
hour(created_at) >= 15
) /*1*/ or
(date(created_at) = CURRENT_DATE() and
hour(created_at) <= 16
) /*2*/
)
And alternative method is:
where status = 'new' and
(created_at >= date_add(CURRENT_DATE(), interval 15-24 hour) and
created_at <= date_add(CURRENT_DATE(), interval 16 hour)
)
The advantage of this approach is that all functions are moved to CURRENT_DATE(). This would allow MYSQL to take advantage of an index on created_at.