datediff() query for multiple dates - mysql

I have a table named orders that contains order_id, order_date and order_shipped. I need to be able to query the difference in days between ordered and shipped for the whole table but only display the order_id's that have 15 or more days between them and I have no idea how to build that query.

Basically you want to select the ids where the date difference is at least 15.
SELECT order_id
FROM orders
WHERE datediff(order_shipped, order_date) >= 15
This could be slow if there are many orders, because the function result cannot be indexed and needs to be calculated every time.

Related

MySQL: Select count of returning vs. new rows in MySQL with period

I have database table in MySQL, which consist of the following fields:
id
user_id
timestamp
The table is a simple log of visitors. I am trying to get the following numbers in one query:
Distinct user_id's for a specific time period (30 days)
Amount of these user_id's, which already exist in the table, regardless of time period
I have been able to do it within the period with this simple query:
SELECT
COUNT(DISTINCT user_id) AS 'count_distinct',
COUNT(user_id) AS 'count_all'
FROM
table
WHERE
timestamp BETWEEN CURDATE() - INTERVAL 30 DAY AND CURDATE();
Running this query gives me the count of distinct user_id's and the count of all user_id's within the time period. I can then apply the math myself to get the count of new vs. returning visitors - for that period. What I am trying to figure out is how many distinct user_id's, who visited within 30 days, who has also visited at any previous point in time.
I hope you can help me solve this.

Selecting average prices for each of the last 30 days in SQL

Have this query that I use to get the average price of the products in a product category for each of the last 30 days:
SELECT DATE(bsbp.date) AS pricedate, UNIX_TIMESTAMP(DATE(bsbp.date)) AS unixdate,
ROUND(AVG((bsbp.price / 100) * (bc.exchangerate / 100)), 0) AS avgprice
FROM bd_shopbikesprices bsbp, bd_categoriesshopbikes bcsb, bd_shopbikes bsb,
bd_shops bs, bd_currencies bc
WHERE bsbp.shopbikeid = bcsb.shopbikeid AND bcsb.categoryid = 94
AND bsbp.shopbikeid = bsb.id AND bsb.shopid = bs.id AND bs.feedcurrencyid = bc.id
AND bsbp.price > 0
GROUP BY DATE(bsbp.date) ORDER BY pricedate DESC LIMIT 30
Problem is that the table with the prices (bsbp) only contains price changes, i.e. the last price of each product where the price was different than the previous price of the product (or where the product was new and therefore didn't have a previous price).
Like this:
shopbikeid|date|price
890061|2016-07-27 02:50:01|29999
890061|2016-07-21 03:21:51|49999
890061|2016-07-17 21:20:55|29999
890061|2016-06-30 04:41:36|49999
Currently the query takes the average new prices for each day, which isn't the actual average price since the average new prices only covers the products where the price was changed/new products.
My question is how the query should be rewritten so each daily average is the average price of all products on that day, including products where the prices was changed before that day.
Can it be done somehow with a nice query? (the database is a MySQL database)
I had a similiar case and solved it using the following approach:
Create a temporary table tmpLatestDates from your price table, in which you group by the product and use MAX(date)
Create another temporary table tmpLatestPrices: Join tmpLatestDateswith your price table on product and date, only keeping the rows from tmpLatestDates. This gives you the latest price for each product.
Run your original query on tmpLatestPrices
When you do this with large datasets you'll want to add indexes to the temporary tables after you created them. Also don't forget to drop the temporary tables after you're done.
The most practical way of handling it would be to put all queries in a stored procedure.
Edit: You can follow the same logic using subqueries, but I find the temp. table approach easier to follow plus it simplifies maintenance later on.

How to get the average price for the X most recent rows based on date?

I am looking to calculate moving averages over variable dates.
My database is structured:
id int
date date
price decimal
For example, I'd like to find out if the average price going back 19 days ever gets greater than the average price going back 40 days within the past 5 days. Each of those time periods is variable.
What I am getting stuck on is selecting a specific number of rows for subquery.
Select * from table
order by date
LIMIT 0 , 19
Knowing that there will only be 1 input per day, can I use the above as a subquery? After that the problem seems trivial....
if you only have one input per day you don't need id, date can be your primary id? Am i missing something? Then use select sum
SELECT SUM(price) AS totalPrice FROM table Order by date desc Limit (most recent date),(furthest back date)
totalPrice/(total days)
I may not understand your question
Yes you can use that as a sub-query like this:
SELECT
AVG(price)
FROM
(SELECT * FROM t ORDER BY date DESC LIMIT 10) AS t1;
This calculates the average price for the latest 10 rows.
see fiddle.

How to deal with counting items by date in MySQL when the count for a given date increment is 0?

I'm looking to make some bar graphs to count item sales by day, month, and year. The problem that I'm encountering is that my simple MySQL queries only return counts where there are values to count. It doesn't magically fill in dates where dates don't exist and item sales=0. This is causing me problems when trying to populate a table, for example, because all weeks in a given year aren't represented, only the weeks where items were sold are represented.
My tables and fields are as follows:
items table: account_id and item_id
// table keeping track of owners' items
items_purchased table: purchaser_account_id, item_id, purchase_date
// table keeping track of purchases by other users
calendar table: datefield
//table with all the dates incremented every day for many years
here's the 1st query I was referring to above:
SELECT COUNT(*) as item_sales, DATE(purchase_date) as date
FROM items_purchased join items on items_purchased.item_id=items.item_id
where items.account_id=125
GROUP BY DATE(purchase_date)
I've read that I should join a calendar table with the tables where the counting takes place. I've done that but now I can't get the first query to play nice this 2nd query because the join in the first query eliminates dates from the query result where item sales are 0.
here's the 2nd query which needs to be merged with the 1st query somehow to produce the results i'm looking for:
SELECT calendar.datefield AS date, IFNULL(SUM(purchaseyesno),0) AS item_sales
FROM items_purchased join items on items_purchased.item_id=items.item_id
RIGHT JOIN calendar ON (DATE(items_purchased.purchase_date) = calendar.datefield)
WHERE (calendar.datefield BETWEEN (SELECT MIN(DATE(purchase_date))
FROM items_purchased) AND (SELECT MAX(DATE(purchase_date)) FROM items_purchased))
GROUP BY date
// this lists the sales/day
// to make it per week, change the group by to this: GROUP BY week(date)
The failure of this 2nd query is that it doesn't count item_sales by account_id (the person trying to sell the item to the purchaser_account_id users). The 1st query does but it doesn't have all dates where the item sales=0. So yeah, frustrating.
Here's how I'd like the resulting data to look (NOTE: these are what account_id=125 has sold, other people many have different numbers during this time frame):
2012-01-01 1
2012-01-08 1
2012-01-15 0
2012-01-22 2
2012-01-29 0
Here's what the 1st query current looks like:
2012-01-01 1
2012-01-08 1
2012-01-22 2
If someone could provide some advice on this I would be hugely grateful.
I'm not quite sure about the problem you're getting as I don't know the actual tables and data they contain that generates those results (that would help a lot!). However, let's try something. Use this condition:
where (items.account_id = 125 or items.account_id is null) and (other-conditions)
Your first query is perfectly acceptable. The fact is you don't have data in the mysql table and therefore it can't group any data together. This is fine. You can account for this in your code so that if the date does not exist, then obviously there's no data to graph. You can better account for this by ordering the date value so you can loop through it accordingly and look for missed days.
Also, to avoid doing the DATE() function, you can change the GROUP BY to GROUP BY date (because you have in your fields selected DATE(pruchase_date) as date)

Getting the average number of orders per day using mysql

I have the following table structure:
ID, User_ID, DateTime
Which stores a user id and datetime of an order purchased. How would I get the average number of orders a day, across every row?
In pseudo code I'm thinking:
Get total number of orders
Get number of days in range (from first row to last row).
Divide 1. by 2. to get average?
So it would return me a value of 50, or 100?
Thanks
Since you know the date range, and you are not guaranteed to have and order on these dates, you can't just subtract the max(date) from min(date), but you know the number of days before you run the query, therefore simply:
select count(*) / <days>
from mytable
where DateTime between <start> and <end>
Where you supply the indicated values because you know them.
select DATEDIFF(NOW(), date_time) as days, AVG(count(*))
from table
group by days
I have not tested the query, its just the idea, I guess it should work.