Select last_update lower then date less X days from another table - mysql

I'll try to explain as better as is possible. We have a table with products, all products have a last_update datetime field. and I have a table with a list of suppliers, and i need to get each day count from the suppliers subtract to current date, and check if the last date is lower than today.
for now I have this, that proven to not work:
update products_ean p
join astra_settings_automation a on a.id_supplier = p.id_supplier
set p.active = 0
where p.last_update < now() - INTERVAL 5 DAY and p.last_update < DATE_SUB(
CURDATE(), INTERVAL (
select Days_Until_Clean_Stock
from astra_settings_automation
where astra_settings_automation.id_supplier=p.id_supplier
) DAY
);
how can i solve this? all the "old" ones need to be deactivated.
thanks in advance

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

How to convert SQL result into percentage

I am trying to find the percentage increase in the last 7 days but I am a little stuck. Currently in the SQL query I have created, you can get the total of the new accounts in the last 7 days. But now, how can I improve to be able to return the result in percentage?
Here is the SQL query done so far.
Thanks
SELECT COUNT(DISTINCT account_type)
FROM account
WHERE date_created > NOW() - INTERVAL 7 DAY
You could create a temporary table with two columns, say 'old count' and 'new count'. Populate the table with the values you get from your SELECT queries.
Then, retrieve the values from the temp table to calculate the percentage difference and delete the temp table.
With purpose to run all in one query you may consider next query:
SELECT
/* Count for previous period. */
beforeCount,
/* Count for current period. */
afterCount,
/* Simple math, just calculating percentage. */
(beforeCount * 100) / afterCount AS percent
FROM (
SELECT
/* Select count for previous period. */
(
SELECT COUNT(DISTINCT account_type)
FROM account
WHERE date_created BETWEEN NOW() - INTERVAL 14 DAY AND NOW() - INTERVAL 7 DAY
) AS beforeCount,
/* Select count for current period. */
(
SELECT COUNT(DISTINCT account_type)
FROM account
WHERE date_created > NOW() - INTERVAL 7 DAY
) AS afterCount
) AS tmp
you can try below way calculate last 7days count and then calculate before 7days all then calculate percentage
select max(last7days_count) as last7days_count,
max(before7days_count) as before7days_count,
((max(before7days_count)*1.00)/max(last7days_count))*100.00 as percentage from
(
SELECT COUNT(DISTINCT account_type) as last7days_count, 0 as before7days_count
FROM account
WHERE date_created > NOW() - INTERVAL 7 DAY
union all
SELECT 0 as last7days_count COUNT(DISTINCT account_type) as before7days_count
FROM account
WHERE date_created < NOW() - INTERVAL 7 DAY
) as T
Conditional aggregation might work. Use a CASE to only count the new and another to only count the old accounts.
SELECT count(DISINCT CASE
WHEN date_created > NOW() - INTERVAL 7 DAY THEN
account_type
END)
/
count(DISTINCT CASE
WHEN date_created <= NOW() - INTERVAL 7 DAY THEN
account_type
END)
* 100 increase
FROM account;
With Temporary table you can do in like :
create temporary table storeCount IF NOT EXISTS (
oldCount INT(10) not null,
newCount INT(10) not null
);
insert into percentage (oldCount,newCount)
values
(SELECT COUNT(DISTINCT acc1.account_type)FROM account acc1, SELECT COUNT(DISTINCT acc2.account_type)
FROM account acc2 WHERE acc2.date_created > NOW() - INTERVAL 7 DAY);
select ((newCount/oldCount)*100) as percentage from storeCount;
drop temporary table IF EXISTS storeCount;
Assuming you have one row per account, you don't need distinct. I am guessing you want:
SELECT (SUM(date_created >= CURDATE() - INTERVAL 7 DAY) * 100/
SUM(date_created > CURDATE() - INTERVAL 7 DAY)
) as percent_increase
FROM account

How can I add days to a date in MYSQL in a query

I am trying to add 5 days to a date in MYSQL in a query. This is what I have done:
SELECT * FROM sales INNER JOIN partner on user_id = idpartner WHERE DATE((end_date) + 5) >= DATE(NOW()) ORDER BY end_date ASC LIMIT 0,50000
But this is not showing the list of sales which has ended. Can someone please tell me where I am making a mistake.
It looks like you want rows where end_date is later than five days ago.
The best way to get that is with
WHERE end_date >= CURDATE() - INTERVAL 5 DAY
The business of adding integers to dates doesn't work in MySQL (it's an Oracle thing). So you need to use the INTERVAL n unit syntax.
You'll notice that my WHERE clause above is functionally equivalent to
WHERE DATE(end_date) + INTERVAL 5 DAY >= DATE(NOW())
But, the first formulation is superior to the second for two reasons.
if you mention end_date in a WHERE clause without wrapping it in computations, your query can exploit an index on that column and can run faster.
DATE(NOW()) and CURDATE() both refer to the first moment of today (midnight). But CURDATE() is a bit simpler.
To fix the original query, you can use DATE_ADD with the INTERVAL keyword:
SELECT
*
FROM
sales
INNER JOIN
partner ON user_id = idpartner
WHERE
DATE_ADD(end_date, INTERVAL 5 DAY) >= DATE(NOW())
ORDER BY end_date ASC
LIMIT 0 , 50000
Said that, I wouldn't recommend applying functions such as DATE_ADD on columns, as it means that the database won't be able to use an index on end_date. Therefore, I would modify the query to:
SELECT
*
FROM
sales
INNER JOIN
partner ON user_id = idpartner
WHERE
end_date <= DATE_ADD(DATE(NOW()), INTERVAL 5 DAY)
ORDER BY end_date ASC
LIMIT 0 , 50000
As you can see, in the second alternative all functions are applied on constants and not on columns (end_date).
You can try
DATE_ADD() here is the
Link
Select DATE_ADD(DATE_FORMAT(NOW(),'%Y-%m-%d'),INTERVAL 1 DAY) FROM DUAL

How to count records as "0" that have value "0" when using WHERE x = 1

I have a table structure that looks like this:
I have a perfectly working query that counts how many records there have been per day the last 30 days. It looks likes this:
SELECT DATE(timestamp) AS date, COUNT(id) AS emails FROM 'emails WHERE timestamp >= now() - interval 1 month GROUP BY DATE(timestamp)
This outputs the following which is perfectly fine:
However, the next thing seems too difficult for me to imagine. Now I want to count how many records there have been per day the last 30 days BUT only where newsletter = 1.
I've tried to put a WHERE statement looking like this:
SELECT DATE(timestamp) AS date, COUNT(*) AS emails, nyhedsbrev FROM emails WHERE timestamp >= now() - interval 1 month AND nyhedsbrev = 1 GROUP BY DATE(timestamp)
... And that outputs the following:
The problem is, that its omitting the records with newsletter = 0 and there by I cant compare my first query against the new one, as the dates doesnt match. I know that is because I use WHERE newsletter = 1.
In stead of omitting the record I want a query that just puts a "0" from that date. How can I do this? The final query should be outputting this:
You should be able to simply use SUM() and IF() to get the desired output:
SELECT
DATE(timestamp) AS date,
COUNT(*) AS emails,
SUM(IF(nyhedsbrev > 0, 1, 0)) as nyhedsbrev_count
FROM
emails
WHERE
timestamp >= now() - interval 1 month
GROUP BY
DATE(timestamp)
SQLFiddle DEMO
Edit: You might even be able to simplify it, since it's a boolean, and simply use SUM(nyhedsbrev), but this REQUIRES that nyhedsbrev is only 0 or 1:
SELECT
DATE(timestamp) AS date,
COUNT(*) AS emails,
SUM(nyhedsbrev) as nyhedsbrev_count
FROM
emails
WHERE
timestamp >= now() - interval 1 month
GROUP BY
DATE(timestamp)
Possibly best to get a list of the dates and then left join that against sub queries to get the counts you require.
Something like this
SELECT Sub1.date, Sub2.emails, IFNULL(Sub3.emails, 0)
FROM (SELECT DISTINCT DATE(timestamp) AS date
FROM emails
WHERE timestamp >= now() - interval 1 month) Sub1
LEFT OUTER JOIN (SELECT DATE(timestamp) AS date, COUNT(id) AS emails
FROM emails WHERE timestamp >= now() - interval 1 month
GROUP BY DATE(timestamp)) Sub2
ON Sub2.date = Sub3.date
LEFT OUTER JOIN (SELECT DATE(timestamp) AS date, COUNT(*) AS emails
FROM emails
WHERE timestamp >= now() - interval 1 month AND nyhedsbrev = 1
GROUP BY DATE(timestamp)) Sub3
ON Sub1.date = Sub3.date
(you can probably optimise one subselect of this away, but I have done it in full to make it obvious how it is working)
Assuming newsletter is boolean 1/0 values then this might give you the table that you want:
SELECT DATE(timestamp) AS date, COUNT(*) AS emails, nyhedsbrev
FROM emails WHERE timestamp >= now() - interval 1 month GROUP BY DATE(timestamp),nyhedsbrev ;
Just adding another GROUP BY parameter.

Rolling 30 day uniques in sql

Suppose you have a table of the form:
create table user_activity (
user_id int not null,
activity_date timestamp not null,
...);
It's easy enough to select the number of unique user_id's in the past 30 days.
select count(distinct user_id) from user_activity where activity_date > now() - interval 30 day;
But how can you select the number of unique user_ids in the prior 30 days for each of the past 30 days? E.g. uniques for 0-30 days ago, 1-31 days ago, 2-32 days ago and so on to 30-60 days ago.
The database engine is mysql if it matters
You could try using a sub query:
SELECT DISTINCT `activity_date` as `day`, (
SELECT count(DISTINCT `user_id`) FROM `user_activity` WHERE `activity_date` = `day`
) as `num_uniques`
FROM `user_activity`
WHERE `activity_date` > NOW() - INTERVAL 30 day;
This should give you the number of unique users for each day. However, I haven't tested this since I don't have the DB to work with.
I haven't tried this in MySQL, but hopefully the syntax is right. If not, maybe it will point you in the right direction. First, I often employ a Numbers table. It can be a physical table simply made up of numbers or it can be a generated/virtual/temporary table.
SELECT
N.number,
COUNT(DISTINCT UA.user_id)
FROM
Numbers N
INNER JOIN User_Activity UA ON
UA.activity_date > NOW() - INTERVAL 30 + N.number DAY AND
UA.activity_date <= NOW() - INTERVAL N.number DAY
WHERE
N.number BETWEEN 0 AND 30
GROUP BY
N.number
I'm not familiar with the whole INTERVAL syntax, so if I got that wrong, please let me know and I'll try to correct it.
If you get the days number for todays date and mod it by 30 you get the offset of the current day. Then you add that to each number for a date and divide the result by 30, this gives you the group of days. Then group your results by this number. So in code something like this:
select count(distinct user_id), (to_days(activity_date)+(to_days(now()) % 30)) / 30 as period
from user_activity
group by (to_days(activity_date)+(to_days(now()) % 30)) / 30
I will leave calculating the reverse numbering of period up to you (hint: take the period number for the current date as "max" and subtract period above and add 1.)