Count distinct attribute values based on two other columns in SQL - mysql

I've got a table with three key attributes, like below:
I want to query it to figure out the number of items sold based on item type and date sold. So the output might look something like this:
My query looks like this:
SELECT SaleItem AS 'Item Sold', SaleDay AS 'Item Sell Day', COUNT(DISTINCT SaleNumber) AS 'Number'
FROM Sales
GROUP BY SaleDay, SaleItem
This is returning a table with the SaleItems organized properly, but the count is the total number sold, excluding the SaleDay attribute.
It's returning the total number of sales per item instead of only the sales on that day per item. So, if 7 pens were sold Monday and 6 on Tuesday it should return two tuples (7, Monday, Pen) and (6, Tuesday, pen). Currently, its returning (13, Monday, pen) and (13, Tuesday, pen).
How can I fix this query?

You complecated your question, by next simply show the input & output so you will get answer faster, any way, here is your solution: you don't need the distinct
SELECT SaleItem AS 'Item Sold',
SaleDay AS 'Item Sell Day',
COUNT(SaleItem) AS 'Number'
FROM Sales
GROUP BY SaleDay, SaleItem

Related

Merge two table values into one and rolling the value to next day adding/subtracting stock movement

I have two simple tables and a Date table:
Table1:
Date, ShopID, ItemID, Stock movement as Qty (-)
Table2:
Date, ShopID, ItemID, Stock movement as Qty (+)
Date table:
Date, which generates for each day
What I want to do is the following:
Merge the two tables into one, adding the intem movements together by Date,ShopID,ItemID,
so I have a stock value for day 1. I want to roll this value to the following day, and add
the following day's movements to it. If there is no stock movement, then just roll up last
day's value.
Example:
Day 1:
Shop12 restocks 100pc of Item66 and sells 30pc of the same item.
For day 1, I should get the 70pc of Item66 at Shop12
Day 2:
Shop12 restocks 40pc of Item66 and sells 70pc of the same item.
For day 2, I should already have a start value of 70pc, + 40pc - 70pc. 40pc as a final result
Day 3:
Shop12 sells 15pc of Item66
For day 3, I have a starting value of 40pc from day 2, -15pc. 25pc as a final result
and so on..
I tried to use UNION ALL, making a SUM of the two Qty columns, which is fine, however I didn't
manage to roll the result to the following date. Also I'm having trouble to show all dates, as
my query only generates data to dates that had movements.
My query:
SELECT
DAT.Date
,C.ShopID
,C.ItemID
,C.TOTAL
FROM Table.Date DAT
LEFT JOIN (
SELECT
A.ShopID,
A.Date,
A.ItemID
,SUM(A.Qty) AS TOTAL
FROM (
SELECT [ShopID]
,[Date]
,[ItemID]
,[Qty]
FROM [StockMovement].[StckItems]
UNION ALL
SELECT [ShopID]
,[Date]
,[ItemID]
,QTY*-1 AS QTY
FROM [SalesMovement].[SlsItems]
) A
group by
A.ShopID,A.Date,A.ItemID
) C ON C.Date = DAT.Date
Any tip helps!
Thank you!
UNION, UNION ALL, LAG, join functions
I expected from UNION ALL, to result in a table with all movements from the seperate
tables, which worked. I then made a left join with the Date table so for all dates I have
a value, however I didn't manage to make it work.

Getting average value based on grouped data

I'm trying to find the average of net total for a given month, based on previous years to help show things like seasonal trends in sales.
I have a table called "Invoice" which looks similar to the below (slimmed down for the purpose of this post):
ID - int
IssueDate - DATE
NetTotal - Decimal
Status - Enum
The data I'm trying to get, for example would be similar to this:
(sum of invoices in June 2018 + sum of invoices in June 2019 + sum of invoices in June 2020) divided by number of years covered (3) = Overall average for June
But, doing this for the full 12 months of the year based on all the data (not just 2018 through to 2020).
I'm a bit stumped on how to pull this data. I've tried subqueries and even tried using a SUM within an AVG select, but the query either fails or returns incorrect data.
An example of what I've tried:
SELECT MONTHNAME(`Invoice`.`IssueDate`) AS `CalendarMonth`, AVG(`subtotal`)
FROM (SELECT SUM(`Invoice`.`NetTotal`) AS `subtotal`
FROM `Invoice`
GROUP BY EXTRACT(YEAR_MONTH FROM `Invoice`.`IssueDate`)) AS `sub`, `Invoice`
GROUP BY MONTH(`Invoice`.`IssueDate`)
which returns:
I see two parts to this query, but unsure how to structure it:
A sum and count of all data based on the month
An average based on the number of years
I'm not sure where to go from here and would appreciate any pointers.
Ideally, I'd want to get the totals from rows where "Status" = "Paid", but trying to crack the first part first. Walk before running as they say!
Any guidance greatly appreciated!
Basically you want two levels of aggregation:
SELECT mm, AVG(month_total)
FROM (SELECT YEAR(i.IssueDate) as yyyy, MONTH(i.issueDate) as mm,
SUM(i.`NetTotal`) as month_total
FROM Invoice i
GROUP BY yyyy, mm
) ym
GROUP BY mm;
Just for the Average Amount Part You Could use a query like
Select Date From Your_Table Where Date Like '20__-06-%'
You can arrange it into asc desc order.

Processing columns inside SQL query?

I have the following sample data:
id, user_id, action, date, item_id
(5, 1, 'created', '2016-09-08, 1),
(6, 1, 'sold', '2016-09-14, 1),
(7, 2, 'created', '2016-09-08, 2),
(8, 2, 'sold', '2016-09-30, 2),
(9, 3, 'created', '2016-10-08, 3)
I'm trying to create a Query that returns the percentage of items sold within 1 week. The value of the column: "action" represents if the item has been put up for sale, or sold. How could this look?. Should I do this by using a subquery or?
Expected result should be a single percentage (the number of items sold within 1 week, of the total number of items created).
Assuming that the data is indeed this simple, this can easily be done by joining the same table to itself. The first reference to the sample data can be aliased as created and will filter to items with an action of created. Likewise, the sold table reference will restrict itself to items with an action of sold.
Once that's done, we'll get a row of data that has an item's creation and sold dates. Anything that doesn't have a sold action is simply discarded by an inner join. The built in function datediff(date1, date2) will give us the number of days between our two dates. If this is less than or equal to 7, you know that it was sold within a week.
select
created.id
, created.user_id
, created.item_id
, datediff(created.date, sold.date) as days_to_sell
from
sample_data created
join sample_data sold
on created.item_id = sold.item_id
where
created.action = 'created'
and sold.action = 'sold'
and datediff(created.date, sold.date) <= 7

MySQL, How can I count the amount something happens in a month, and display the sum beside month names?

I need to display 2 columns. First column should have the month name. Second column should show me how many times something was released within each month. e.g:
Month number_of_releases
January 4
March 9
December 2
So far, I have this:
SELECT DISTINCT MONTHNAME(date) AS 'Month',
/*Here is where I need help!*/ AS 'number_of_releases'
FROM table_name;
Without knowing how you are calculating number_of_releases, it's hard to say for certain... but you probably want to group your table by monthname and use a suitable aggregate function to yield the number of releases.
For example, to obtain a count of the number of records within each month:
SELECT MONTHNAME(date) AS Month, COUNT(*) AS number_of_releases
FROM table_name
GROUP BY Month

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)