How to count item from joined table? - mysql

I have 2 tables. sales and payment.
sales table (has around 900.000 records)
item_id | sale_id
------------------
1 | 1
2 | 1
3 | 1
1 | 2
1 | 3
3 | 3
payment table (also has around 900.000 records)
sale_id | payment_method
------------------------
1 | CASH
2 | CREDIT
3 | CASH
I'd like to know top 5 best seller items grouped by payment method. Something like this
item_id | total_sales | payment_method
--------------------------------------
1 | 2 | CASH
3 | 2 | CASH
So far I have
SELECT
a.item_id as item_id,
COUNT(a.item_id) as total_sales,
b.payment_method as payment_method
FROM sales a
LEFT JOIN payment b ON a.sale_id = b.sale_id
GROUP BY a.item_id
ORDER BY COUNT(a.item_id) DESC
However, the result is not correct.
How to get something like this?

Related

SQL LEFT JOIN with COUNT that returns NULL values

I have two tables: one that stores the product id and one which stores total sales per product_id and per sale_date
Table Products
product_id
----------
1
2
3
Table Sales
product_id | sale_date | total
-----------+------------+-------
1 | 2017-01-01 | 1
1 | 2017-02-01 | 1
1 | 2017-03-01 | 1
There is no sales total for product 2 and product 3.
I would like to query the sales table in order to get 0 in front of the months where there is no sale for any product id.
The result I would like to achieve is this:
product_id | month | total
-----------+------------+-------
1 | 2017-01 | 1
1 | 2017-02 | 1
1 | 2017-03 | 1
2 | 2017-01 | 0
2 | 2017-02 | 0
2 | 2017-03 | 0
3 | 2017-01 | 0
3 | 2017-02 | 0
3 | 2017-03 | 0
Right now what I do is this:
SELECT DATE_FORMAT(sale_date, "%m-%Y") as month,
Products.product_id,
COUNT(Sales.product_id) as total
FROM products Products
LEFT OUTER JOIN sales Sales
ON Sales.product_id = Products.product_id
GROUP BY Products.product_id, month
and what I get is:
product_id | month | total
-----------+------------+-------
1 | 2017-01 | 1
1 | 2017-02 | 1
1 | 2017-03 | 1
2 | NULL | 0
3 | NULL | 0
What should I modify to get a row for each month when there is no sale total for any product id? Thank you
Use a cross join to generate the rows, then left in to bring in the values:
select p.product_id, d.sales_date,
coalesce(s.total, 0) as total
from products p cross join
(select distinct sales_date from sales) d left join
sales s
on s.product_id = p.product_id and s.sales_date = d.sales_date
order by p.product_id, d.sales_date;
Note: This assumes that all the dates you want are in sales. I should point out that you can use another source for the dates, if you have one, or list them explicitly.
Could you give a try to this query:
select
distinct p.product_id,
DATE_FORMAT(sale_date, "%m-%Y") as month,
if(p.product_id <> s.product_id, 0,total) as total
from products p,
sales s
order by p.product_id

How to retrieve two SUM() value from two tables based on foreign key and subtract them

I have 3 tables
products table purchase table sale table
+----+---------+ +----+-----------+-------+ +----+------------+--------+
| id | product | | id | product_id| pieces| | id | product_id | pieces |
+----+---------+ +----+-----------+-------+ +----+------------+--------+
| 1 | Tyre | | 1 | 3 | 5 | | 1 | 2 | 3 |
+----+---------+ +----+-----------+-------+ +----+------------+--------+
| 2 | Switch | | 2 | 1 | 3 | | 2 | 1 | 2 |
+----+---------+ +----+-----------+-------+ +----+------------+--------+
| 3 | Ring | | 3 | 2 | 6 | | 3 | 3 | 3 |
+----+---------+ +----+-----------+-------+ +----+------------+--------+ | 4 | Wheel | | 4 | 3 | 4 | | 4 | 2 | 1 |
+----+---------+ +----+-----------+-------+ +----+------------+--------+
I want to SUM() both pieces column in purchase table and sale table based on/GROUP BY product_id. Ex- SELECT products, SUM(pieces) FROM purchase GROUP BY product_id Same query for sale table.
I want to subtract the SUM() result to find out the remaining pieces. Ex- SUM(purchase.pieces) - SUM(sale.pieces) AS balance
And finally I need product name from products table, total pieces of same product in purchase table that means how many times a product has been sold such as Tyre - 5 pieces, same for sale table, and remaining pieces after subtract total sale of a product from total purchase of a product.
How can I do this using PHP and PDO?
you can use SUM() for the pieces column and have the difference to get the balance
SELECT p.id,
p.product,
IFNULL(total_purchase,0) total_purchase,
IFNULL(total_sales,0) total_sales,
IFNULL(total_purchase,0) - IFNULL(total_sales,0) balance
FROM (SELECT pd.id,
pd.product,
SUM(pc.pieces) total_purchase
FROM products pd
LEFT JOIN purchase pc
ON pd.id = pc.product_id
GROUP BY pd.id, pd.product
) p
JOIN (SELECT pd.id,
pd.product,
SUM(sl.pieces) total_sales
FROM products pd
LEFT JOIN sales sl
ON pd.id = sl.product_id
GROUP BY pd.id, pd.product
) s
ON p.id = s.id
ORDER BY p.id
Result
id product total_purchase total_sales balance
1 Tyre 3 2 1
2 Switch 6 4 2
3 Ring 9 3 6
4 Wheel 0 0 0
Something like this should be a good start:
select
products.product
purchases.Total as PurchasedPieces,
sales.Total as SoldPieces
purchases.Total - sales.Total as balance
from
products
left join (select(product_id,SUM(pieces) as Total from purchases group by product_id)) purchases on products.id = purchases.product_id
left join (select(product_id,SUM(pieces) as Total from sales group by product_id)) sales on products.id = sales.product_id

Count the number of orders

I have a table (Table1) with the columns order_item_id customer_id and order_id in which I want to count the number of orders per customer. Unfortunately an order with more than one article has the same order_id
|order_item_id|order_id|customer_id|
| 2 | 30 | 1 |
| 3 | 30 | 1 |
| 4 | 42 | 1 |
| 5 | 33 | 2 |
| 11 | 32 | 3 |
| 12 | 33 | 2 |
| 13 | 33 | 2 |
| 19 | 69 | 3 |
Expected Outcome:
|numberOfOrders|customer_id|
| 2 | 1 |
| 1 | 2 |
| 2 | 3 |
I tried this (and many more):
CREATE TABLE X AS
SELECT
customer_id,
COUNT(order_id) AS `numberOfOrders`
FROM Table1 T1
GROUP BY customer_id;
The problem is, that with this solution it counts every article not the number of orders: so the number of orders for customer 1 is 3 (not 2), for customer 2 is 3 (not 1)....
How can I solve this for a big database with Mysql query?
Try the following solution to SELECT your data as expected:
SELECT COUNT(DISTINCT order_id) AS numberOfOrders, customer_id
FROM table1
GROUP BY customer_id
Demo: http://sqlfiddle.com/#!9/ee8f62/1/0
An option could be to do GROUP twice. First GROUP for the number of items per order, wrapped by a second GROUP for the number of orders per customer:
/* second group */
SELECT customer_id
, count(*) AS number_of_orders
FROM (
/* first group */
SELECT order_id
, customer_id
, count(*) AS order_item_count
FROM Table1
GROUP BY order_id, customer_id
) a
GROUP BY customer_id

Mysql subtract from another table

I have tried to search this forum for an answer but can't seem to find one.
My problem: I have 3 tables. One with items, one with in-going deliveries and one with outgoing deliveries.
Table called items:
id | item_name
----------------
1 | Bike
2 | Helmet
3 | Pedal
4 | Light
Table called ingoing:
id | item_id | quantity
-----------------------
1 | 2 | 5
2 | 3 | 2
3 | 4 | 1
4 | 1 | 5
5 | 2 | 4
6 | 1 | 6
7 | 3 | 5
Table called outgoing:
id | item_id | quantity
-----------------------
1 | 3 | 2
2 | 1 | 1
3 | 2 | 3
4 | 3 | 4
5 | 1 | 2
6 | 2 | 1
7 | 4 | 1
What I want to do is get the total amount in stock by subtracting the outgoing deliveries from the in-going and order it by the item with the least amount.
Maybe there is a better way to do this?
This is the query that I got, but the SUM amounts isn't correct. Can someone help me and explain why the SUM amounts isn't correct and how should I solve this with the best way?
SELECT items.id AS ID,
items.item_name,
Sum(ingoing.quantity) - Sum(outgoing.quantity) AS InStock
FROM items
LEFT JOIN ingoing
ON ingoing.item_id = items.id
LEFT JOIN outgoing
ON outgoing.item_id = items.id
GROUP BY ID
ORDER BY InStock ASC
This is the result I want from this:
ID | item_name | InStock
---------------------------
4 | Light | 0
3 | Pedal | 1
2 | Helmet | 5
1 | Bike | 8
What I Get:
ID | item_name | InStock
---------------------------
4 | Light | 0
3 | Pedal | 2
2 | Helmet | 10
1 | Bike | 16
It can be easy to forget the multiplicative effect of a join. When you encounter problems like this, check the result of the join, prior to filtering/grouping:
SELECT items.id,
items.item_name,
ingoing.id AS ingoing,
outgoing.id AS outgoing
FROM items
LEFT JOIN ingoing
ON ingoing.item_id = items.id
LEFT JOIN outgoing
ON outgoing.item_id = items.id
See it on sqlfiddle.
As you can see, the resultset contains multiple records with the same ingoing.id values, and multiple records with the same outgoing.id values. This is because each ingoing record for a particular item has joined with every outgoing record for that same item: thus there are 4 pedals in the resultset (2 incoming x 2 outgoing), etc.
Aggregating each table by item prior to joining (and thus ensuring that there is only 1 record per item on each side of the join) will achieve what you're after:
SELECT items.id AS ID,
items.item_name,
ingoing.quantity - outgoing.quantity AS InStock
FROM items
LEFT JOIN (
SELECT item_id AS id, SUM(quantity) AS quantity
FROM ingoing
GROUP BY item_id
) AS ingoing USING (id)
LEFT JOIN (
SELECT item_id AS id, SUM(quantity) AS quantity
FROM outgoing
GROUP BY item_id
) AS outgoing USING (id)
ORDER BY InStock ASC
See it on sqlfiddle.
Note that your problem would have been greatly simplified by only having a single underlying table of stock movements, with positive quantities indicating movements in one direction and negative quantities indicating movements in the opposite direction: then a simple groupwise summation of the whole table would yield your desired results.
Try this query:
SELECT items.id AS ID, items.item_name, (SELECT SUM(quantity) from ingoing
WHERE ingoing.item_id = items.id) - (SELECT SUM(quantity) from outgoing WHERE
outgoing.item_id = items.id) AS InStock FROM items ORDER BY InStock ASC;

Calculate price with mysql query

gurus! I am stuck. Catalog items have prices dependent to its quantity. Here example of tables:
items: just item definitions
-------------------------
item_id | item_title
-------------------------
1 | "sample item"
2 | "another item"
items_prices: prices dependent to item quantity.
Less price taken for more quantity of item
----------------------------
item_id | quantity | price
----------------------------
1 | 1 | 100
1 | 5 | 80
1 | 10 | 60
2 | 1 | 120
2 | 3 | 100
cart
-------------------
item_id | quantity
-------------------
1 | 20
2 | 2
Is it possible to get current cart cost with single query?
select sum(x.totalcost)
from (
select c.item_id, c.quantity * ip.price as totalcost
from cart c
join items_prices ip
on c.item_id = ip.item_id
left join items_prices ip2
on ip2.quantity > ip.quantity
and c.quantity >= ip2.quantity
where c.quantity >= ip.quantity
and ip2.quantity is null
) x
The join back onto items_price again lets us filter out any cases where there is a greater quantity which still meets our criteria. This should be getting close to what we're after