To make date changes with if condition in mysql - mysql

for this my query is =
SELECT SalesDate,COUNT(Shape) as pcs,
ROUND(SUM(TotalAmount),2) as amount,
ROUND(SUM(Carat),2) as carat,
ROUND(ROUND(SUM(TotalAmount),2)/ROUND(SUM(Carat),2),2) as avgprice
from `tbl_sales`
WHERE IF((SalesDate = CURDATE() - INTERVAL 1 DAY) = null, SalesDate=CURDATE() - INTERVAL 2 DAY,SalesDate= CURDATE() - INTERVAL 1 DAY)
so this is my response
so in If condition I want to make sure that if the data in yesterday data is null or 0 then it will take day before yesterday

Perhaps something like this:
SELECT SalesDate,COUNT(Shape) as pcs,
ROUND(SUM(TotalAmount),2) as amount,
ROUND(SUM(Carat),2) as carat,
ROUND(ROUND(SUM(TotalAmount),2)/ROUND(SUM(Carat),2),2) as avgprice
FROM `tbl_sales`
GROUP BY SalesDate
HAVING SalesDate = CASE WHEN (SalesDate = CURDATE() - INTERVAL 1 DAY)=0
THEN CURDATE() - INTERVAL 2 DAY
WHEN (SalesDate = CURDATE() - INTERVAL 1 DAY)=1
AND amount IS NULL
THEN CURDATE() - INTERVAL 2 DAY
ELSE CURDATE() - INTERVAL 1 DAY END;
When you do (SalesDate = CURDATE() - INTERVAL 1 DAY) it will return false=0 and true=1. Therefore doing (SalesDate = CURDATE() - INTERVAL 1 DAY) = NULL, although it should be .. IS NULL instead of .. = NULL.. either way, it won't work. Let's inspect the CASE expression in HAVING part.
If it return 0 means there's no matching with date specified, then take 2 days before:
CASE WHEN (SalesDate = CURDATE() - INTERVAL 1 DAY)=0
THEN CURDATE() - INTERVAL 2 DAY
If it has match for the date checking and return 1 BUT with NULL amount, then take 2 days before as well:
WHEN (SalesDate = CURDATE() - INTERVAL 1 DAY)=1
AND amount IS NULL
THEN CURDATE() - INTERVAL 2 DAY
Else take yesterday date:
ELSE CURDATE() - INTERVAL 1 DAY END;
Demo fiddle

You need to cast your column to date:
SELECT SalesDate,COUNT(Shape) as pcs,
ROUND(SUM(TotalAmount),2) as amount,
ROUND(SUM(Carat),2) as carat,
ROUND(ROUND(SUM(TotalAmount),2)/ROUND(SUM(Carat),2),2) as avgprice
from `tbl_sales`
WHERE IF((CAST(SalesDate AS date) = CURDATE() - INTERVAL 1 DAY), CAST(SalesDate AS date) = CURDATE() - INTERVAL 2 DAY, CAST(SalesDate AS date) = CURDATE() - INTERVAL 1 DAY)

Related

How DO I fetch last Week and current week

How do I fetch last week data from monday time (00:00:01) and end on sunday time (23:59:59)...
same as this current week from monday time (00:00:01) and end on sunday time (23:59:59)
WHat I tried!
$query = "SELECT users.name,count(*) as count,
campaign.campaign_name,
campaign.payout_cost*count(*) as totalPrice
FROM users
JOIN transactions on users.uid=transactions.uid
JOIN campaign on campaign.campaign_id_id=transactions.campaign_id
WHERE uid=$uid
AND `date` >= DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())+6 DAY)
AND `date` < DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
GROUP BY campaign.campaign_name_name ";
You are on the right track by avoiding functions like week() on the column -- that just messes up the optimizer. On the other hand, the uid parameter should be passed as a parameter rather than munging the query string.
You want to use the weekday() function because you want weeks to start on a Monday. Just some arcaneness of MySQL: weekday() returns 0 for Monday whereas dayofweek() returns 2 for Monday.
So, the logic for the current week would be:
date >= curdate() - interval weekday(curdate()) day and
date < curdate() + interval 7 - weekday(curdate()) day
For last week, this would be:
date >= curdate() - interval 7 + weekday(curdate()) day and
date < curdate() + interval - weekday(curdate()) day
Notes that curdate() (or current_date) returns the current date with no time component, so no date() is required.
Couple of ways to do it...
select data from tableName
where date between date_sub(now(),INTERVAL 1 WEEK) and now();
select data FROM tableName
wherdate >= curdate() - INTERVAL DAYOFWEEK(curdate())+6 DAY
AND date < curdate() - INTERVAL DAYOFWEEK(curdate())-1 DAY
You can use WEEK() function, which returns the week number for a given date, by adding
AND WEEK(date-INTERVAL 1 DAY) = WEEK(NOW()) - 1 to get current week's data starting from monday upto sunday,
and
AND WEEK(date-INTERVAL 1 DAY) = WEEK(NOW()) - 2 for the previous week's data
into the WHERE condition after WHERE uid=$uid
such as
$query = "SELECT c.campaign_name,
COUNT(*) as total_count,
SUM(c.payout_cost) as total_payout
FROM transactions t
JOIN campaign c
ON c.campaign_id = t.campaign_id
WHERE uid = $uid
AND WEEK(date - INTERVAL 1 DAY) = WEEK(NOW()) - 1
GROUP BY c.campaign_name ";
and replace WEEK(NOW()) - 1 with WEEK(NOW()) - 2, also
Demo

Calculate the day tomorrow and if it is Sunday show two more days - Mysql

I'm trying to make a query where one of the fields shows the units of the orders table that are planned tomorrow, but if tomorrow is Sunday it should be Monday.
I have the table orders and the table format.
Orders table:
id_order, order_date, units
Format table:
id_format, format_type
My query initially is this:
SELECT format_type, units, DATE (NOW () + INTERVAL 1 DAY) as Tomorrow
FROM orders Join format on orders.id_format = format.id_format
WHERE DATE (date_delivery) = DATE (NOW () + INTERVAL 1 DAY)
But it would have to be something similar like this:
SELECT format_type, units, DATE (NOW () + INTERVAL 1 DAY) as Tomorrow
FROM orders Join format on orders.id_format = format.id_format
WHERE (
CASE
WHEN DAYNAME (date) = "Sunday" THEN DATE (order_date) = DATE (NOW () + INTERVAL 2 DAY)
ELSE DATE (order_date) = DATE (NOW () + INTERVAL 1 DAY)
END;
_____EDIT_____
This is the result I wanted
SELECT format.format_type, units, DATE(NOW()) as TODAY
FROM orders Join format on orders.id_format = format.id_formatopeso
WHERE
CASE
WHEN WEEKDAY(now()) = 6 then DATE(order_date) = DATE(NOW() + INTERVAL 2 DAY)
ELSE DATE(order_date) = DATE(NOW() + INTERVAL 1 DAY)
END;
Yuu can simply select what you have in where
SELECT format_type, units,
CASE
WHEN WEEKDAY(date) = 6
then DATE_ADD(curdate(), INTERVAL +2 DAY)
else DATE_ADD(curdate(), INTERVAL +1 DAY)
END as tomorrow_with_sunday_check,
DATE_ADD(curdate(), INTERVAL +1 DAY) as Tomorrow
FROM orders Join format on orders.id_format = format.id_format

MySQL - Get Aggregates For Last 1 Day, 7 Days, 30 Days And Allow For Records To Be Counted In More Than 1 Group

I have a table with the following data:
I am looking to group the rows into the following:
Within the last day (everything within the last 24 hours)
Within the last 7 days (everything within the last week)
Within the last 30 days (everything within the last month)
The end result for the above rows would look something like:
I can group the records into these brackets right now with:
SELECT (CASE WHEN created_at = CURDATE() THEN '1 Day'
WHEN created_at >= CURDATE() - INTERVAL 6 DAY THEN '7 Days'
WHEN created_at >= CURDATE() - INTERVAL 29 DAY THEN '30 Days'
END) AS Timeframe, COUNT(*) AS Count
FROM my_table
GROUP BY (CASE WHEN created_at = CURDATE() THEN '1 Day'
WHEN created_at >= CURDATE() - INTERVAL 6 DAY THEN '7 Days'
WHEN created_at >= CURDATE() - INTERVAL 29 DAY THEN'30 Days'
END)
But this will prevent individual records from being counted more than once. For example, lines 2 and 3 in the first picture needs to be counted in all three brackets (1 day, 7 days, and 30 days) - while lines 6 through 9 only needs to be counted in the 30 days bracket.
How would you do this with MySQL?
It is easiest to do this as columns, rather than rows:
SELECT SUM(created_at = CURDATE()) as today
SUM(created_at >= CURDATE() - INTERVAL 6 DAY) as last_7_days,
SUM(created_at >= CURDATE() - INTERVAL 29 DAY) as last_30_days,
SUM(created_at < CURDATE() - INTERVAL 29 DAY) as older
FROM my_table;
If you want your response in several rows, instead of just one with several columns, take #Gordon Linoff as your starting point... but perform the queries "one row at at time" (it won't be as efficient, because you visit the table 4 times instead of 1!):
-- Row for the 1 day timeframe
SELECT '1 Day' AS `Timeframe`, SUM(created_at = CURDATE()) AS `Count`
FROM my_table
UNION
-- Row for the 7 days timeframe...
SELECT '7 Days' AS `Timeframe`, SUM(created_at >= CURDATE() - INTERVAL 6 DAY) AS `Count`
FROM my_table
UNION
SELECT '30 Days' AS `Timeframe`, SUM(created_at >= CURDATE() - INTERVAL 29 DAY) AS `Count`
FROM my_table
UNION
SELECT 'Older' AS `Timeframe`, SUM(created_at < CURDATE() - INTERVAL 29 DAY) AS `Count`
FROM my_table ;
If you can use MariaDB instead of MySQL, you can use a WITH, which will allow the query to be efficient again:
WITH stats AS
(
SELECT SUM(created_at = CURDATE()) as today,
SUM(created_at >= CURDATE() - INTERVAL 6 DAY) as last_7_days,
SUM(created_at >= CURDATE() - INTERVAL 29 DAY) as last_30_days,
SUM(created_at < CURDATE() - INTERVAL 29 DAY) as older
FROM my_table
)
-- Convert to rows with negligible overhead
SELECT '1 Day' AS `Timeframe`, today FROM stats
UNION
SELECT '7 Days', last_7_days FROM stats
UNION
SELECT '30 Days', last_30_days FROM stats
UNION
SELECT 'Older', older FROM stats ;
In both cases, you'll get (as of 2017-07-25):
Timeframe | today
:-------- | ----:
1 Day | 0
7 Days | 4
30 Days | 8
Older | 0
dbfiddle here

Get number of entries per multiple date intervals using single query

SELECT COUNT(*) FROM `table` WHERE `datetime` > SUBDATE(NOW(), INTERVAL 1 DAY)
This will get number of entries during last day. But is it possible to get number of entries for multiple intervals without having to send variation of this query multiple times (INTERVAL 1 DAY, INTERVAL 1 WEEK, INTERVAL 1 MONTH, ...)?
You need CASE WHEN expression to accomplish that.
SELECT
COUNT(CASE WHEN DATE(`datetime`) >= CURDATE() - INTERVAL 1 DAY AND DATE(`datetime`) < CURDATE() THEN 1 END) AS lastDay,
COUNT(CASE WHEN DATE(`datetime`) >= CURDATE() - INTERVAL 7 DAY AND DATE(`datetime`) < CURDATE() THEN 1 END ) AS lastSevenDays,
COUNT(*) AS lastThirtyDays
FROM `table`
WHERE
DATE(`datetime`) >= CURDATE() - INTERVAL 30 DAY
How to use CASE WHEN expression
Note: If your requirement is to get result of last day, last 7 days and last 30 days then go with this query.
EDIT:
If you have an index on datetime field then the above query will fail to use that index. Please use the query given below in order to utilize the index on datetime.
SELECT
COUNT(CASE WHEN DATE(`datetime`) >= CURDATE() - INTERVAL 1 DAY AND DATE(`datetime`) < CURDATE() THEN 1 END) AS lastDay,
COUNT(CASE WHEN DATE(`datetime`) >= CURDATE() - INTERVAL 7 DAY AND DATE(`datetime`) < CURDATE() THEN 1 END ) AS lastSevenDays,
COUNT(*) AS lastThirtyDays
FROM `table`
WHERE
`datetime` >= (NOW() - INTERVAL 30 DAY - INTERVAL HOUR(NOW()) HOUR - INTERVAL MINUTE(NOW()) MINUTE - INTERVAL SECOND(NOW()) SECOND)

How do I retrieve data for the previous month in SQL

I want to get data for the dates between 2015-05-01 and 2015-06-01 using SQL.
Please help me with the query.
The query I used is:
select *,count(id) as multiple_visitors
from table1
where id=123
and (date(server_time) between (CURDATE() - INTERVAL 31 DAY) AND CURDATE())
group by user_id having count(id)>1
You can do this with month() and year():
where month(server_time) = month(curdate() - interval 1 month) and
year(server_time) = year(curdate() - interval 1 month)
However, I recommend a slightly more complex expression:
where server_time >= date_sub(date_sub(curdate(), interval - day(curdate()) + 1 day), interval 1 month) and
server_time < date_sub(curdate(), interval - day(curdate()) + 1 day)
The advantage is that there are no functions on server_time, so the database engine can use an index, if appropriate.
As a note: the expression date_sub(curdate(), interval - day(curdate()) + 1 day) gets midnight on the first day of the month.
Try using "WHERE" with MONTH(date).
Like this:
SELECT * FROM Table
WHERE MONTH(date) = 1