I have 2 Tables.
The first table stores the products.
id I Product Name
1 I Apple
2 I Bread
3 I Butter
... Many more
The second table stores the overall purchases with a date
product_id I purchasedoverall I date
1 I 2 I 1.2.14
1 I 10 I 3.2.14
3 I 3 I 4.2.14
... Many more
Attention: In the example, at 1.2.14 2 apples where sold, at 3.2.14 8 more apples, so there are 10 stored in purchasedoverall.
What I want from the Database is:
Give me the products purchased in the last week, ordered by how many items where bought IN THE LAST WEEK.
Until now, I do it this (bad) way:
I get all products
SELECT * FROM products
Store them in an array
I iterate over the array to get the purchased count in the last week
SELECT MAX(c.purchasedoverall)-MIN(c.purchasedoverall) as purchased
FROM products as a, puchased as c
WHERE c.product_id = {product-id from the array}
AND c.date >= NOW() - INTERVAL 1 WEEK
ORDER BY c.date
I combine the arrays an sort them
My question: Can I do this with one MySQL-Query?
Assuming pr.name is unique:
SELECT pr.name,
COALESCE(MAX(pu.purchasedoverall)-MIN(pu.purchasedoverall),0) purchased
FROM products pr
LEFT JOIN purchased pu
ON pu.product_id = pr.id
AND pu.date > CURDATE() - INTERVAL 1 WEEK
GROUP BY pr.name
ORDER BY purchased DESC, pr.name
But as pointed out in the comments you should really be storing data at the resolution that you need it, not performing complex queries to enhance the resolution..
Whatever the difficulties of obtaining the data structure and the code associated, it is almost certainly much easier to refactor this than build a system atop a flawed design.
SELECT a.id, a.product_name, MAX(c.purchasedoverall)-MIN(c.purchasedoverall) as total_purchased
FROM products a
left join puchased c
ON c.product_id=a.id
AND c.date >= NOW() - INTERVAL 1 WEEK
group by a.id
ORDER BY total_purchased;
Related
I have a table documenting purchases from customers, with one row per purchase:
CustomerID | ProductID
1 | 1000
1 | 2000
1 | 3000
2 | 1000
3 | 1000
3 | 3000
... | ...
I am using the following code to find the ten customers with the greatest number of overlapping products with customer #1 (first result is the one with the most overlap etc):
SELECT othercustomers.CustomerID, COUNT(DISTINCT othercustomers.ProductID)
FROM `purchases` AS thiscustomer
JOIN `purchases` AS othercustomers ON
thiscustomer.CustomerID != othercustomers.CustomerID
AND thiscustomer.ProductID = othercustomers.ProductID
WHERE thiscustomer.CustomerID = '1'
GROUP BY othercustomers.CustomerID
ORDER BY COUNT(DISTINCT othercustomers.ProductID) DESC
LIMIT 10
The code yields the expected output (Customer ID + total number of overlapping products with customer #1).
I would now like the query to exclude customers with overlapping purchases who have purchased more than 1000 different products, because these are bulk buyers who purchase the entire stock and whose purchase history therefore has no meaning when searching for customers with a similar taste.
In other words, if customer #500 had bought >1000 different products, I want him/her excluded from the results when searching for customers with a similar taste to that of customer #1 - even if customer #500 has bought all three products that customer #1 had bought and would ordinarily rank first in similarity/overlap.
I suppose some HAVING is in order, but I cannot seem to figure out what the appropriate condition is.
Thanks!
I think that HAVING won't do what you want, since it will only give you the total count of overlaping products, while you want the total count of products for the other customer.
You could filter with a correlated subquery in the WHERE clause:
SELECT othercustomers.CustomerID, COUNT(DISTINCT othercustomers.ProductID)
FROM `purchases` AS thiscustomer
JOIN `purchases` AS othercustomers ON
thiscustomer.CustomerID != othercustomers.CustomerID
AND thiscustomer.ProductID = othercustomers.ProductID
WHERE
thiscustomer.CustomerID = '1'
AND (
SELECT COUNT(DISTINCT ProductID)
FROM `purchases` AS p
WHERE p.CustomerID = othercustomers.CustomerID
) < 1000
GROUP BY othercustomers.CustomerID
ORDER BY COUNT(DISTINCT othercustomers.ProductID) DESC
LIMIT 10
For performance, you want an index on purchases(CustomerID, ProductID).
So what i'm trying to do here, is that i am trying to count the number of repeat users (users who made more than one order) in a period of time, let it be month day or year, the case here is months
i'm currently running mysql mariadb and i'm pretty much a beginner in mysql, i've tried multiple subqueries but all have failed till now
This is what i have tried so far ..
This returns all the number of users with no ordering count condition
Since people are asking for sample data, here is what the data is looking like at the moment:
Order_Creation_Date - User_ID - Order_ID
2019-01-01 123 1
2019-01-01 123 2
2019-01-01 231 3
2019-01-01 231 4
This is the query i am using to get the result but it keeps on returning total number of users within the month
select month(o.created_at)month,
year(o.created_at)year,
count(distinct o.user_uuid) from orders o
group by month(o.created_at)
having count(*)>1
and this returns the number of users as 1 ..
select month(o.created_at)month,
year(o.created_at)year,
(select count(distinct ord.user_uuid) from orders ord
where ord.user_uuid = o.user_uuid
group by ord.user_uuid
having count(*)>1) from orders o
group by month(o.created_at)
Expected result will be from the sample data above
Month Count of repeat users
1 2
If you want the number of users that make more than one purchase in January, then do two levels of aggregations: one by user and month and the other by month:
select yyyy, mm, sum( num_orders > 1) as num_repeat_users
from (select year(o.created) as yyyy, month(o.created) as mm,
o.user_uuid, count(*) as num_orders
from orders o
group by yyyy, mm, o.user_uuid
) o
group by yyyy, mm;
I think you should try something like this which will return USer_ID list Month and Year wise who ordered more that once for the period-
SELECT
[user_uuid],
MONTH(o.created_at) month,
YEAR(o.created_at) year,
COUNT(o.user_uuid)
FROM orders o
GROUP BY
MONTH(o.created_at),YEAR(o.created_at)
HAVING COUNT(*) > 1;
For more, if you are looking for the count that how many users placed more that one order, you can just place the above query as a sub query and make a count on column 'user_uuid'
I have a table of sales and a table of sales items. Each sale can have multiple items. The sale also has a sales agency and its the agency ID that is used to search (in this example agency id 8).
So the pseudo query is count how many of a specific product type (in the items table are found for a specific agency between 2 dates.
Table layout
agency --->sale--->item1
|-->item2
My query is
SELECT (SELECT COUNT(DISTINCT(sale_id))
FROM sales_order_items AS si
WHERE si.sale_id = s.id AND si.product_type ='1')as COUNT
FROM sales as s
JOIN agency as a ON s.sales_person = a.agency_id
WHERE s.created >= '2018-01-01 00:00:00' AND s.created <= '2018-01-08 23:59:59' AND a.agency_id = '8'
GROUP BY s.sales_person
If I run this, I get
COUNT
1
and if I remove the GROUP BY I get
COUNT
1
1
1
0
1
0
BUT I want the SUM of the numbers so in this example above ...4 items found!
I am using the DISTINCT because there could be many items on the same sale of the product type i am searching for but I just want to find out how many sales have THAT PRODUCT TYPE rather than a count of items on the order. Where am I going wrong?
Help appreciated
Keith
I have two tables, one table called "tbl_materiales", and another called "tbl_pedidos".. In the table called tbl_materiales" I have information about all my products, Like Description, and the most important "Price"...
In my table "tbl_pedidos", i register all information of products that the user register in the website.
For example:
tbl_materiales:
IdProduct Description Price
5 Product one 8
6 Product three 10
7 Product four 15
tbl_pedidos
IdProduct Quantity Month
5 10 January
6 5 January
7 2 February
So, I want to know all the earnings PER month...
I want to have this: The column earnings is the multiplication of tbl_pedidos.Quantity * tbl_materiales.Price, obviously it depends of the price of the product, and the quantity sold out.
Month Earnings
January 130
February 30
Now, I have this, but it doesn't bring me the correct information...
SELECT tbl_pedidos.Mes
, (SUM(tbl_pedidos.Cantidad) * tbl_materiales.Precio) as Total
FROM tbl_pedidos
INNER JOIN tbl_materiales
ON tbl_pedidos.IdMaterial = tbl_materiales.IdMaterial
GROUP BY tbl_pedidos.Mes
ORDER BY tbl_pedidos.Fecha;
SELECT tbl_pedidos.Mes , SUM(tbl_pedidos.Cantidad*tbl_materiales.Precio) as Total
FROM tbl_pedidos
INNER JOIN tbl_materiales
ON tbl_pedidos.IdMaterial = tbl_materiales.IdMaterial
GROUP BY tbl_pedidos.Mes
ORDER BY tbl_pedidos.Fecha;
Check http://sqlfiddle.com/#!9/de665b/1
The query can be like :
SELECT tbl_p.Month
,sum(as tbl_m.Price*TP.Quantity) AS Earnings
FROM tbl_materiales AS tbl_m
JOIN tbl_pedidos AS tbl_p
ON tbl_m.IdProduct = tbl_p.IdProduct
GROUP
BY tbl_p.Month;
In this case I have used Where instead of Join, maybe de next sentence resolve your problem:
select TP.Month,sum(TM.Price*TP.Quantity) as Earnings
from TBL_Pedidos TBP,TBL_Materiales TM
where TP.IdProduct = TM.Id_Product
group by TP.Month
Group by is the solution
I'm fairly new to SQL and am having difficulty solving a problem.
'What are the total sales across all products for the salespeople that sell at least one unit of each of the five individual products with the highest sales by unit? Make sure that the query returns the total sales dollars in descending order. Only consider sales that take place over the six complete months prior to a #target_date parameter.'
3 tables exist in the DB.
SalesPerson (SalesPersonID,SalesYTD)
SalesOrderHeader (SalesOrderID,OrderDate,ShipDate)
SalesOrderDetail (SalesOrderID,SalesOrderDetailID,OrderQty,ProductID,UnitPrice)
This is where I'm at so far. I need to compile what I have into one statement and make necessary revisions. Please help!
To capture the top 5 highest sales by unit, the following SYNTAX should work:
SELECT
ProductID,
SUM(Orderqty*Unitprice)
FROM SalesOrderDetail
GROUP BY ProductID
WHERE Orderqty >=1
AND COUNT(productID) =5
ORDER BY SUM(Orderqty*Unitprice) DESC
LIMIT 5;
For the target_date parameter, I think it would be something along these lines?
SELECT
SalespersonID AS ‘Sales Representative’,
SalesYTD AS ‘Total Sales’, target_date
FROM Salesperson
WHERE target_date BETWEEN ‘01-DEC-13’ AND ’01-May-14’;
For the top five highest sales, I would rather propose the slightly simplified
select productid, sum(orderqty * unitprice) as sales
from salesorderdetail
group by productid
order by sales desc
limit 5
and for the six months prior to #target_date something like
where orderdate between date_sub(#target_date, interval 6 months) and #target_date
Assuming a FK SalesOrderDetail(SalesPersonID), you can then join the tables and top five sales as
select p.*
from salesperson p
join salesorderheader h on h.salespersionid = p.salespersionid
join salesorderdetail d on d.salesorderid = h.salesorderid
join (select productid, sum(orderqty * unitprice) as sales
from salesorderdetail
group by productid
order by sales desc
limit 5) t5 on t5.productid = d.productid
where h.orderdate between date_sub(#target_date, interval 6 months) and #target_date
order by p.salesytd desc