I am having trouble wrapping my head around a query I'm supposed to write.
I've got two tables: stock and articles
Columns in articles:
id
name
price
Columns in stock:
id
articleId
tstamp_in (yyyy-mm-dd hh:mm:ss)
For every article that is delivered to me by my suppliers, I create a new row in the stock table. That means that every article can have multiple rows in the stock table. One of my colleges asked if I could supply a list that shows him all new articles, so in other words all records from stock that have a tstamp_in value higher than last midnight.
I came to the following query but I really cant figure out how to get the result I am looking for.
SELECT *
FROM stock
LEFT JOIN articles ON stock.articleId=articles.id
WHERE tstamp_in>'2015-01-12 00:00:00'
This gives me all records in the stock table created after last midnight. However this does not mean that there aren't any previous records. What I'm trying to figure out is how I can get this in one query.
In short:
Select all from stock grouped by articleId where tstamp_in > 2015-01-12 00:00:00 and not having records with that articleId before 2015-01-12 00:00:00
Is this possible?
Think of the the problem a bit differently. For what articles is the earliest tstamp_in today? That leads you to an aggregation and having:
select s.articleId
from stock s
group by s.articleId
having min(tstamp_in) > '2015-01-12'
Related
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.
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.
I need to get the row where the due_date field has the last month in every year.
For eg: if I have 3 entries with due_date field like 2014-5-21,2014-6-21,2014-7-21
I need the last row in year 2014, that will be 2014-7-21, like wise in 2015 and the following years.
Can someone help me out with this.
I tried but nothing worked out
SELECT distinct(year(due_date)) FROM `vw_mortgage_repayment_schedule_org`
where mortgage_id ='AREM-1408614735-VLASFAQ8VI'
and month(due_date) = max(month())
I need all the last rows for the given mortgage of every year eg- 2014,2015,2016 etc
I think if you group by the year of the due_date, that might just about give you what you need, given that we search for the max month in the select, and group by the year. Possibly. Can we have your table structure?
SELECT year(due_date), month(max(due_date)), max(due_date)
FROM `vw_mortgage_repayment_schedule_org`
where mortgage_id ='AREM-1408614735-VLASFAQ8VI'
GROUP BY year(due_date)
I have a query that shows me the number of calls per day for the last 14 days within my app.
The query:
SELECT count(id) as count, DATE(FROM_UNIXTIME(timestamp)) as date FROM calls GROUP BY DATE(FROM_UNIXTIME(timestamp)) DESC LIMIT 14
On days where there were 0 calls, this query does not show those days. Rather than skip those days, I'd like to have a 0 or NULL in that spot.
Any ideas for how I can achieve this? If you have any questions as to what I'm asking please let me know.
Thanks
I don't believe your query is "skipping over NULL values", as your title suggests. Rather, your data probably looks something like this:
id | timestamp
----+------------
1 | 2014-01-01
2 | 2014-01-02
3 | 2014-01-04
As a result, there are no rows that contain the missing date, so there are no rows to be counted. The answer is that you need to generate a list of all the dates you want and then do a LEFT or RIGHT JOIN to it.
Unfortunately, MySQL doesn't make this as easy as other databases. There doesn't seem to be an effective way of generating a list of anything inline. So you'll need some sort of table.
I think I would create a static table containing a set of integers to be subtracted from the current date. Then you can use this table to generate your list of dates inline and JOIN to it.
CREATE TABLE days_ago_list (days_ago INTEGER);
INSERT INTO days_ago_list VALUES
(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13)
;
Then:
SELECT COUNT(id), list_date
FROM (SELECT SUBDATE(CURDATE(), days_ago) AS list_date FROM days_ago_list) dates_to_list
LEFT JOIN (SELECT id, DATE(FROM_UNIXTIME(timestamp)) call_date FROM calls) calls_with_date
ON calls_with_date.call_date = dates_to_list.list_date
GROUP BY list_date
It is very important that you group by list_date; call_date will be NULL for any days without calls. It is also important to COUNT on id since NULL ids will not be counted. (That ensures you get a correct count of 0 for days with no calls.) If you need to change the dates listed, you simply update the table containing the integer list.
Here is a SQL Fiddle demonstrating this.
Alternatively, if this is for a web application, you could generate the list of dates code side and match up the counts with the dates after the query is done. This would make your web app logic somewhat more complicated, but it would also simplify the query and eliminate the need for the extra table.
create a table that contains a row for each date you want to ensure is in the results, left outer join with results of your current query, use temp table's date, count of above query and 0 if that count is null
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)