I have following example
SELECT
oa.country_id,
s.country_id,
(IF(
s.country_id = oa.country_id,
DATE_ADD(DATE(so.created_at), INTERVAL 2 DAY),
DATE_ADD(DATE(so.created_at), INTERVAL 5 DAY)
)
) AS inter
And I would like to add where condition as follow:
WHERE inter >= CURDATE() - INTERVAL DAYOFWEEK(CURDATE())+6 DAY
AND inter > CURDATE() - INTERVAL DAYOFWEEK(CURDATE())-1 DAY;
Is it possible add where to "inter" result?
Or I need to repeat the same if statement query in WHERE twice?
Thnak you.
You cannot use inter in the WHERE clause because column aliases are not understood there. You could use a CTE or subquery.
However, MySQL extends the use of HAVING for non-aggregation queries. So you can add a HAVING clause:
HAVING inter >= CURDATE() - INTERVAL DAYOFWEEK(CURDATE())+6 DAY AND
inter > CURDATE() - INTERVAL DAYOFWEEK(CURDATE())-1 DAY;
Note: The logic of the expression does not look correct -- but this is the expression in your question. The first part is more restrictive, so the second part is redundant. Perhaps you intend < for one of them.
Related
I'm trying to turn two count queries with date conditions (the ones below) into one query.
SELECT COUNT(*) as yesterday FROM orders WHERE DATE(timedate) = DATE(NOW() - INTERVAL 1 DAY)
SELECT COUNT(*) as yesterday FROM orders WHERE DATE(timedate) = DATE(NOW() - INTERVAL 2 DAY)
Following the advice of another answer I created the following, but that doesn't seem to work syntax-wise, and I'm not quite sure why. Is there another way to do this? I can't find a similar question on this
SELECT
SUM(IF(DATE(timedate) = DATE(NOW() - INTERVAL 1 DAY))) AS testcount1,
SUM(IF(DATE(timedate) = DATE(NOW() - INTERVAL 2 DAY))) AS testcount2
FROM
orders
You're missing the output values for the IF expression. Also you should use CURRENT_DATE() so you don't need to convert to a DATE:
SELECT
SUM(IF(DATE(timedate) = CURRENT_DATE() - INTERVAL 1 DAY, 1, 0)) AS testcount1,
SUM(IF(DATE(timedate) = CURRENT_DATE() - INTERVAL 2 DAY, 1, 0)) AS testcount2
FROM
orders
Note that MySQL treats boolean expressions as 1 (true) or 0 (false) in a numeric context, so you can actually SUM the expression without needing the IF:
SELECT
SUM(DATE(timedate) = CURRENT_DATE() - INTERVAL 1 DAY) AS testcount1,
SUM(DATE(timedate) = CURRENT_DATE() - INTERVAL 2 DAY) AS testcount2
FROM
orders
You want conditional aggregation. I would phrase the query as follows:
SELECT
SUM(
timedate >= CURRENT_DATE - INTERVAL 1 DAY
and timedate < CURRENT_DATE
) AS testcount1,
SUM(
timedate >= CURRENT_DATE - INTERVAL 2 DAY
and timedate < CURRENT_DATE- INTERVAL 1 DAT
) AS testcount2
FROM orders
Details:
this uses a nice feature of MySQL, that evaluates false/true conditions as 0/1 in numeric context
no date functions are applied on the timedate column : instead, we do litteral date comparisons. This is much more efficient, since the database can possibly take advantage of an index on the datetime column
You might also want to add a WHERE clause to the query:
WHERE
timedate >= CURRENT_DATE - INTERVAL 2 day
AND timedate< CURRENT_DATE
First off, thank you in advance.
I have 2 queries that I am working with as I would like to compare last week to the previous week...
Getting Last Week
SELECT keyword,
SUM(users_desktop) AS desktop_last_week
FROM js
WHERE country='US'
AND day >= curdate() - INTERVAL DAYOFWEEK(curdate())+6 DAY
AND day < curdate() - INTERVAL DAYOFWEEK(curdate())-1 DAY
GROUP BY keyword
ORDER BY desktop_last_week DESC
LIMIT 10;
Getting Previous Week
SELECT keyword,
SUM(users_desktop) AS desktop_previous_week
FROM js
WHERE country='US'
AND day >= curdate() - INTERVAL DAYOFWEEK(curdate())+12 DAY
AND day < curdate() - INTERVAL DAYOFWEEK(curdate())-7 DAY
GROUP BY keyword
ORDER BY desktop_previous_week DESC
LIMIT 10;
What I would like to do is combine these queries so that I can then ORDER BY the division of desktop_last_week/desktop_this_week to find keywords that are trending up (ie: searched a lot more this week than last week)
Any idea on how to combine these together?
This is called conditional aggregation. Use where clauses from your existing queries to do it.
SELECT keyword,
Sum(CASE
WHEN day >= Curdate() - INTERVAL Dayofweek(Curdate())+6 day
AND day < Curdate() - INTERVAL Dayofweek(Curdate())-1 day THEN
users_desktop
ELSE 0
end) AS desktop_last_week,
Sum(CASE
WHEN day >= Curdate() - INTERVAL Dayofweek(Curdate())+12 day
AND day < Curdate() - INTERVAL Dayofweek(Curdate())-7 day THEN
users_desktop
ELSE 0
end) AS desktop_prev_last_week
FROM js
WHERE country = 'US'
GROUP BY keyword
ORDER BY desktop_prev_last_week / desktop_this_week DESC
LIMIT 10
Use Union!
You can get 2 Queries to one with that. If you want to order that then put it into a subquery
You could expand the where clause to contain both time ranges and move the logic of differentiating between them to case expressions inside the sums. By the way, using the between operator instead of a >= and < pair would make the query itself a tad easier to read:
SELECT keyword,
SUM(CASE WHEN day BETWEEN
(CURDATE() - INTERVAL DAYOFWEEK(curdate()) + 6 DAY) AND
(CURDATE() - INTERVAL DAYOFWEEK(curdate()) - 1 DAY)
THEN users_desktop
END) AS desktop_last_week,
SUM(CASE WHEN day BETWEEN
(CURDATE() - INTERVAL DAYOFWEEK(curdate()) + 12 DAY) AND
(CURDATE() - INTERVAL DAYOFWEEK(curdate()) - 7 DAY)
THEN users_desktop
END) AS desktop_previous_week
FROM js
WHERE country = 'US'
GROUP BY keyword
ORDER BY desktop_last_week DESC, desktop_previous_week DESC
LIMIT 10;
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.
I have this SQL statement. It works, and I need to add another one condition.
I need to sort it by date. occurence - is my date row.
SELECT dd.caption, COUNT(t.occurence)
FROM transaction t
INNER JOIN dict_departments dd
ON dd.id = t.terminal_id
GROUP BY dd.caption
How to add this condition:
WHERE t.occurence BETWEEN (CURRENT_DATE() - INTERVAL 1 MONTH)
to my query.
Try this:
WHERE t.occurrece BETWEEN current_date() AND dateadd(month,1,current_date())
The function dateadd is a SQL SERVER function, but the rest of the clause is standard SQL.
BETWEEN requires two arguments, a start point and an end point. If your end point is the current time, you have two options:
Using BETWEEN:
WHERE t.occurence BETWEEN (CURRENT_DATE() - INTERVAL 1 MONTH) AND NOW()
Using simple comparison operator:
WHERE t.occurence >= (CURRENT_DATE() - INTERVAL 1 MONTH)
If you want to filter dates from 1 month ago till now:
WHERE (t.occurrece BETWEEN DATE_ADD(CURDATE(), INTERVAL -1 MONTH) AND CURDATE()) = 1
or
WHERE (t.occurrece BETWEEN ADDATE(CURDATE(), INTERVAL -1 MONTH) AND CURDATE()) = 1
I have a table containing data about events and festivals with following columns recording their start and end dates.
Start_Date
End_Date
date format is in YYYY-MM-DD. I need to fetch event details with the following condition.
Need to fetch all events which start with a current month and there end dates can be anything say currentDate+next30days.
I am clear about end date concept. but not sure how I can fetch data whose start dates are in a current month.
For this, I need to compare current year and current month against the Start_Date column in my database.
Can anyone help me to point out as how I can do that?
select * from your_table
where year(Start_Date) = year(curdate())
and month(Start_Date) = month(curdate())
and end_date <= curdate() + interval 30 day
I don't like either of the other two answers, because they do not let the optimizer use an index on start_date. For that, the functions need to be on the current date side.
So, I would go for:
where start_date >= date_add(curdate(), interval 1 - day(curdate()) day) and
start_date < date_add(date_add(curdate(), interval 1 - day(curdate()) day), interval 1 month)
All the date functions are on curdate(), which does not affect the ability of MySQL to use an index in this case.
You can also include the condition on end_date:
where (start_date >= date_add(curdate(), interval 1 - day(curdate()) day) and
start_date < date_add(date_add(curdate(), interval 1 - day(curdate()) day), interval 1 month)
) and
end_date <= date_add(curdate(), interval 30 day)
This can still take advantage of an index.
DateTime functions are your friends:
SELECT
*
FROM
`event`
WHERE
(MONTH(NOW()) = MONTH(`Start_Date`))
AND
(`End_Date` <= (NOW() + INTERVAL 30 DAY))
AND
(YEAR(NOW()) = YEAR(`Start_Date`))
Comparing the year and month separately feels messy. I like to contain it in one line. I doubt it will make a noticeable difference in performance, so its purely personal preference.
select * from your_table
where LAST_DAY(Start_Date) = LAST_DAY(curdate())
and end_date <= curdate() + interval 30 day
So all I'm doing is using the last_day function to check the last day of the month of each date and then comparing this common denominator. You could also use
where DATE_FORMAT(Start_Date ,'%Y-%m-01') = DATE_FORMAT(curdate(),'%Y-%m-01')