MySQL SUM column1 if column2 equals today and column3 equals specific test - mysql

I was cruising along setting up a production schedule at work, but I have been stuck on something that seems like it should be so easy.
I have a table called orders with columns for date, item and quantity.
I am trying to total the quantity of each item for a specific date.
I've been stuck for hours trying all sorts of things. Not sure if I am even close.
For example:
SELECT * FROM orders WHERE date_prod='2011-10-01' AS 'today';
SELECT item, date_prod, SUM( quantity )
FROM today
GROUP BY item
HAVING date_prod = '2011-10-01'
LIMIT 0 , 30
Tried playing around a bunch already. VIEW is not a practical way for me to do this because I want to be able to query a specific date far into the future and see what the total quantity is for each item ordered that day.
Something tells me this should be easy but I'm pretty new at this.
Thanks in advance!

What about:
SELECT item, SUM( quantity ) AS total
FROM orders
WHERE date_prod = '2011-10-01'
GROUP BY item

Related

MySQL: Get the average of a column

I have a table name invoices. There is a column named user and late_fee. I am trying to find out the percentage of late invoices compared to how many invoices total.
He has 16 invoices, which 2 of those invoices are late. I feel like this should be an easy pie query but I can't figure it out for the life of me?
You could use something like this. It gets the count of the late_fee depending on it's value.
select sum( case
when late_fee = 1
then 1
else 0
end
)
/ count(*)
from invoices
group
by user
As #Ravinder pointed out, in MySQL this is also valid (does not work on other platforms though):
select sum( late_fee = 1
)
/ count(*)
from invoices
group
by user

Get count on two different date columns and group by date

I have table containing two DATE columns. TS_customer and TS_verified
I am searching for a way to get a result where in the first column I have dates where either someone created a user (TS_customer) or someone got verified (TS_verified).
In the second column I want count(TS_customer) grouped by the first column.
The third column I want count(TS_verified) grouped by the first column.
It might be 0 customers verified on a sign up date, and in another case 0 signups on a date someone got verified.
I guess it should be an easy one, but I've spent so many hours on it now. Would really appreciate some help. I need this for a graph in excel, so i basicly want how many customers signed up and how many got verified one day without having the hassle to have two selects and combinding them manually.
EDIT: link to SQLfiddle http://sqlfiddle.com/#!2/b14fc/1/0
Thanks
First, we need the list of days.
That looks like this http://sqlfiddle.com/#!2/b14fc/14/0:
SELECT DISTINCT days
FROM (
SELECT DISTINCT DATE(TS_customer) days
FROM customer
UNION
SELECT DISTINCT DATE(TS_verified) days
FROM customer
) AS alldays
WHERE days IS NOT NULL
ORDER BY days
Next we need a summary of customer counts by day. That's pretty easy http://sqlfiddle.com/#!2/b14fc/16/0:
SELECT DATE(TS_customer) days, COUNT(TS_customer)
FROM customer
GROUP BY days
The summary of verifications by day is similarly easy.
Next we need to join these three subqueries together http://sqlfiddle.com/#!2/b14fc/29/0.
SELECT alldays.days, custcount, verifycount
FROM (
SELECT DISTINCT DATE(TS_customer) days
FROM customer
UNION
SELECT DISTINCT DATE(TS_verified) days
FROM customer
) AS alldays
LEFT JOIN (
SELECT DATE(TS_customer) days, COUNT(TS_customer) custcount
FROM customer
GROUP BY days
) AS cust ON alldays.days = cust.days
LEFT JOIN (
SELECT DATE(TS_verified) days, COUNT(TS_verified) verifycount
FROM customer
GROUP BY days
) AS verif ON alldays.days = verif.days
WHERE alldays.days IS NOT NULL
ORDER BY alldays.days
Finally, if you want 0 displayed rather than (null) for days when there weren't any customers and/or verifications, change the SELECT line to this http://sqlfiddle.com/#!2/b14fc/30/0.
SELECT alldays.days,
IFNULL(custcount,0) AS custcount,
IFNULL(verifycount,0) AS verifycount
See how that goes? We build up your result set step by step.
I'm a bit confused on why you created a fiddle that can not hold null values on the TS_Customer and then mention that the field can hold null values.
Having said that, I've modified the solution to work with null values and still be pretty efficient and simple:
SELECT days, sum(custCount) custCount, sum(verifCount) verifCount FROM (
SELECT DATE(TS_customer) days, count(*) custCount, 0 verifCount
FROM customer
WHERE TS_customer IS NOT NULL
GROUP BY days
UNION ALL
SELECT DATE(TS_verified) days, 0, count(*)
FROM customer
WHERE TS_verified IS NOT NULL
GROUP BY days
) s
GROUP BY days
I've also created a different fiddle containing some null values here.

MySql retrieve products and prices

I would like to retrieve a list of all the products, with their associated prices for a given period.
The Product table:
Id
Name
Description
The Price table:
Id
Product_id
Name
Amount
Start
End
Duration
The most important thing to not here, is that a Product can have mutliple prices, even over the same period, but not with the same duration.
For example, a price from "2013-06-01 -> 2013-06-08" and another from "2013-06-01 -> 2013-06-05"
So my aim is to retrieve, for a given period, the lists of all products, paginated by 10 product for example, joined to the prices existant over the period.
The basic way to do so would be:
SElECT *
FROM product
LEFT JOIN prices ON ...
WHERE prices.start >= XXX And prices.end <= YYY
LIMIT 0,10
The problem while using this simple solution, is that I can't retrieve only 10 Products, but 10 Products*Prices, which is not acceptable in my case.
So the solution would be:
SElECT *
FROM product
LEFT JOIN prices ON ...
WHERE prices.start >= XXX And prices.end <= YYY
GROUP BY product.id
LIMIT 0,10
But the problem here is, i'll only retrieve "1" price for each product.
So I wonder what would be the best way to handle this.
I could for example use a group function, like "group_concat", and retrieve in a field all the prices in a string, like "200/300/100" and so on. That seem weird, and would need work on server-language side to transform to a readable information, but it could work.
Another solution would be to use different column for each prices, depending on duration:
SELECT
IF( NOT ISNULL(price.start) AND price.duration = 1, price.amount , NULL) AS price_1_day
---- same here for all possible durations ---
From ...
Thta would work too i guess (i'm not really sure if this is possible however), but I may need to create about 250 columns to cover all possibilities. Is that a safe option ?
Any help will be much appreciated
I believe that a group_concat would be the best way forward on this, as its very purpose is to aggregate multiple pieces of data relating to a particular column.
However, adapting on peterm's SQL fiddle, this is possible to do in 1 query if using user defined variables. (If one ignores the initial query for setting the vars)
http://dev.mysql.com/doc/refman/5.7/en/user-variables.html
SET #productTemp := '', #increment := 0;
SElECT
#increment := if(#productTemp != Product_id, #increment + 1, #increment) AS limiter,
#productTemp :=Product_id as Product_id,
Product.name,
Price.id as Price_id,
Price.start,
Price.end
FROM
Product
LEFT JOIN
Price ON Product.Id=Price.Product_id
WHERE
`start` >= '2013-05-01' AND `end` <= '2013-05-15'
GROUP BY
Price_id
HAVING
limiter <=2
What we're doing here is only incrementing the user defined var "incrementer" only when the product id is not the same as the last one that was encountered.
As aliases cannot be used in the WHERE condition, we must GROUP by the unique ID (in this case price ID) so that we can reduce the result using HAVING. In this case, I have a full result set that should include 3 Product IDs, reduced to only showing 2.
Please note: This is not a solution I would recommend on large data sets, or in a production enviornment. Even the mysql manual makes a point of highlighting that user defined vars can behave somewhat erratically depending on what paths the optimizer takes. However, I have used them to great effect for some internal statistics in the past.
Fiddle: http://sqlfiddle.com/#!2/96c92/3
It's hard to tell without sample data and desired output but you can try something like this
SElECT p.*, q2.*
FROM
(
SElECT Product_id
FROM Price
WHERE `start` >= '2013-05-01' AND `end` <= '2013-05-15'
GROUP BY Product_id
LIMIT 0,10
) q1 JOIN
(
SELECT *
FROM Price
WHERE `start` >= '2013-05-01' AND `end` <= '2013-05-15'
) q2 ON q1.Product_id = q2.Product_id JOIN product p
ON q1.Product_id = p.Id
Here is SQLFiddle demo

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)

Filter weekly from daily data and pick first occurence of the week

Assume you have a table with a stock time series on a daily basis.
Now you need to filter one data point per week, because you need weekly data for some analysis. You don't to have weekly averages, since this would leave much of the variation out.
This would be my initial approach, but it's not clear which of the data points falling in a given week is selected.
SELECT date, price from stock_series
GROUP BY WEEK(date)
1 How do I make sure it's always the first data point existing for a given week that gets picked?
EDIT:
2 If the above query stayed the way it is - which data point gets chosen every week? What's the MySQL logic in this case? Or is it just unpredictible?
If you want to have a better control over it, you could try using a subquery :
SELECT date,price
FROM stock_series
WHERE date IN
(
SELECT MIN(inner.date)
FROM stock_series inner
GROUP BY WEEK(inner.date)
) GROUP BY date
I've added GROUP BY date in the main query because you probably have more than one entry per day, otherwise it could be ommited.
EDIT:
or try joining with it:
SELECT date,price
FROM stock_series
JOIN
(
SELECT MIN(date) AS innerdate
FROM stock_series
GROUP BY WEEK(date)
) inner ON date=innerdate;
You can order by date ascending, which should give you just the first result of the WEEK() group.
SELECT date,price from stock_series
GROUP BY WEEK(date)
ORDER BY date