MySQL pivot to make a row into a colum - php

I have three tables, products, customers, order
Product:
id | name |
1 | milk |
2 | bread|
3 | Pea |
Customer:
id | name | category
1 | James | retailer
2 | Paul | vendor
3 | Dave | retailer
Order:
id | product_id | customer_id | qty | price
1 | 1 | 2 | 23 | 50
2 | 2 | 2 | 4 | 30
3 | 3 | 2 | 6 | 10
4 | 2 | 1 | 9 | 30
5 | 3 | 1 | 2 | 10
6 | 1 | 3 | 6 | 50
7 | 3 | 3 | 7 | 10
When i do a query to show transactions by customers with category of vendor like
SELECT customer.name, product.name as pname, order.qty, order.price FROM customer, product, order
WHERE customer.id = order.customer_id
AND product.id = order.product_id AND customer.category = "vendor"
i will get something like:
name | pname | qty | price
Paul | milk | 23 | 50
Paul | bread | 4 | 30
Paul | pea | 6 | 10
I want this instead:
name | milk | bread | pea | total
Paul | 23 | 4 | 6 | 90
While that of retailers will look like this:
SELECT customer.name, product.name as pname, order.qty, order.price FROM
customer, product, order
WHERE customer.id = order.customer_id
AND product.id = order.product_id AND customer.category = "retailer"
I will get a table like this:
name | pname | qty | price
James | bread | 9 | 30
James | pea | 2 | 10
Dave | milk | 6 | 50
Dave | pea | 7 | 10
But i want this instead:
name | milk | bread | pea | total
James | 0 | 9 | 2 | 40
Dave | 6 | 0 | 7 | 60

Simply use conditional aggregation for pivoting columns. And be sure to use explicit joins instead of the deprecated implicit join as former has been the standard for 25 years in ANSI-92.
SELECT c.name,
SUM(CASE WHEN p.name = 'milk' THEN o.qty ELSE 0 END) as milk,
SUM(CASE WHEN p.name = 'bread' THEN o.qty ELSE 0 END) as bread,
SUM(CASE WHEN p.name = 'pea' THEN o.qty ELSE 0 END) as pea,
SUM(o.price) AS Total
FROM `customer` c
INNER JOIN `order` o
ON c.id = o.customer_id
INNER JOIN `product` p
ON p.id = o.product_id
WHERE c.category = 'vendor' -- same for retailer
GROUP BY c.name

I think that you cannot have this response structure directly from one simple select
name | milk | bread | pea | total
James | 0 | 9 | 2 | 40
Dave | 6 | 0 | 7 | 60
because your database is getting one row foreach retailers/customer order.
I know that using a server language like PHP or Java you will can handle the data and retrive like you want.

Related

summing 2 columns data in single table with different condition

I have 2 tables jornal_main and journal_item , my journal_main table has got
id | po_no | period | post_date | vendor
1 | PO123 | 12 | 2018-02-12 | XYZ
2 | PO234 | 12 | 2018-02-13 | ABC
journal_item is
id | ref_id | type | sku | qty | desc
1 | 1 | poo | A123 | 12 | Order
2 | 1 | poo | B234 | 20 | Order
3 | 2 | por | A123 | 2 | Receive
4 | 2 | por | A123 | 3 | Receive
5 | 2 | por | B234 | 6 | Receive
Desired output is
po_no | date | vendor | item | ordered_qty | received_qty | balance
po123 | 2018-02-12 | XYZ | A123 | 12 | 5 | 7
po123 | 2018-02-12 | ABC | B234 | 20 | 6 | 14
i am not getting how to combine 2 queries in a single query. Here i have 2 queries which gives me ordered_qty and received_qty
for ordered_qty
select journal_main.id, journal_main.po_no, journal_main.post_date, journal_main.vendor, journal_item. sku, SUM(journal_item.qty) AS Oqty FROM journal_main INNER JOIN journal_item ON journal_main.id=journal_item.ref_id WHERE journal_item.type='poo' GROUP BY journal_item.sku, journal_main.id
for received_qty
select journal_main.id, journal_main.po_no, journal_main.post_date, journal_main.vendor, journal_item. sku, SUM(journal_item.qty) AS Rqty FROM journal_main INNER JOIN journal_item ON journal_main.id=journal_item.ref_id WHERE journal_item.type='por' GROUP BY journal_item.sku, journal_main.id
Just use conditional aggregation:
select ji.ref_id,
sum(case when ji.desc = 'Order' then qty else 0 end) as ordered,
sum(case when ji.desc = 'Receive' then qty else 0 end) as received,
sum(case when ji.desc = 'Order' then qty else - qty end) as total
from journal_item ji
where ji.desc in ('Order', 'Receive')
group by ji.ref_id;
This just provides the aggregation columns. You should be able to join in the rest of the columns that you want.

MySQL Statement to joins 2 tables and sum same items qty

I have 2 tables, customer and transaction.
Customer:
--------------------------------------------
ID | Name | Tel
--------------------------------------------
1 | Peter | 123 4567
2 | John | 456 1234
3 | Alice | 789 4561
4 | Amy | 741 8525
Transaction:
--------------------------------------------
CustID | Books | Pens | Ruler
--------------------------------------------
1 | 2 | 0 | 1
2 | 1 | 0 | 0
1 | 0 | 3 | 0
1 | 0 | 0 | 1
2 | 1 | 1 | 1
3 | 0 | 2 | 2
I need the following
Results:
-------------------------------------------------------------------
ID | Name | Tel | Books | Pens | Ruler
-------------------------------------------------------------------
1 | Peter | 123 4567 | 2 | 3 | 2
2 | John | 456 1234 | 2 | 1 | 1
3 | Alice | 789 4561 | 0 | 2 | 2
4 | Amy | 741 8525 | 0 | 0 | 0
Basically it will sum the Books, Pens and Ruler of the same Customer.
I've tried:
$sql = "select
`customer`.id,
`custmaster`.name,
`custmaster`.tel,
`transaction`.id,
`transaction`.books,
`transaction`.pens,
`transaction`.ruler,
from `customer`
left join `transaction`
on `customer`.id=`transaction`.custid
ORDER BY `customer`.id ASC";
But display none. :( I do understand that I needed the sum() function somewhere. Anybody can help?
Use SUM and GROUP BY.
SELECT c.id, c.name, c.tel, SUM(t.books) as books, SUM(t.pens) AS pens, SUM(t.ruler) AS ruler
FROM customer AS c
LEFT JOIN transactions AS t ON c.id = t.custid
GROUP BY c.id
ORDER BY c.id
Try this way
select
`customer`.id,
`custmaster`.name,
`custmaster`.tel,
`transaction`.id,
sum(`transaction`.books) as books,
sum(`transaction`.pens) as pens,
sum(`transaction`.ruler) as ruler,
from `customer`
left join `transaction`
on `customer`.id=`transaction`.custid
Group by `customer`.id,`customer`.Name
ORDER BY `customer`.id ASC";

agent sales report, sums all their sales and minimized display result by total sales

i have 3 table user, products and sales
user
UID | NAME
1 | agent1
2 | agent2
3 | agent3
4 | agent4
5 | agent5
products
PID | PNAME
1 | P1
2 | P2
3 | P3
sales
SID | UID | PID | SALES_CREATED
1 | 3 | 1 | 2013-07-13 01:15:04
2 | 1 | 1 | 2013-07-13 01:25:34
3 | 3 | 1 | 2013-07-13 02:01:34
4 | 3 | 1 | 2013-07-13 02:45:34
5 | 5 | 1 | 2013-07-13 02:56:34
6 | 5 | 1 | 2013-07-13 03:21:34
7 | 2 | 3 | 2013-07-13 03:38:34
8 | 3 | 2 | 2013-07-13 03:51:34
9 | 4 | 2 | 2013-07-13 04:25:34
10 | 3 | 1 | 2013-07-13 04:45:04
11 | 1 | 3 | 2013-07-13 04:55:34
12 | 2 | 2 | 2013-07-13 05:01:34
13 | 1 | 3 | 2013-07-13 05:15:34
14 | 5 | 3 | 2013-07-13 05:36:34
15 | 5 | 3 | 2013-07-13 06:21:34
where the results of sales per agent is: (sort by user UID)
user | P1 | P2 | P3 |
agent1 | 1 | 0 | 2 |
agent2 | 0 | 1 | 1 |
agent3 | 4 | 1 | 0 |
agent4 | 0 | 1 | 0 |
agent5 | 2 | 0 | 2 |
now, i want a result to sort user that has a greatest sale by P1 and a minimum of 3 result only, and the result will be like this
user | P1 | P2 | P3 |
agent3 | 4 | 1 | 0 |
agent5 | 2 | 0 | 2 |
agent1 | 1 | 0 | 2 |
can you guys give me a best mysql_query to show that result?
Oh, something like this...
SELECT uid
, SUM(pid=1) p1
, SUM(pid=2) p2
, SUM(pid=3) p3
FROM sales
GROUP
BY uid
ORDER
BY p1 DESC
, p2 DESC
, p3 DESC;
+-----+------+------+------+
| uid | p1 | p2 | p3 |
+-----+------+------+------+
| 3 | 4 | 1 | 0 |
| 5 | 2 | 0 | 2 |
| 1 | 1 | 0 | 2 |
| 2 | 0 | 1 | 1 |
| 4 | 0 | 1 | 0 |
+-----+------+------+------+
If handling the display logic at the application level, then your query can be simplified to something more scalable, like this...
SELECT uid
, pid
, COUNT(*)
FROM sales
GROUP
BY uid,pid;
I am only answering because (1) I am bored, and (2) I wanted a brain teaser exercise. I typically do not like to answer when people post and run (don't respond to anyone's comments/posts), or provide what they have tried (no query).
If you want better/more help on SO in the future, it would be beneficial to post the query that you have tried, and when using complex/diverse data like this to create a sqlfiddle - http://sqlfiddle.com/
So with that caveat, here is how you can get your desired results
SELECT
user.NAME as user,
SUM(PID=1) as P1,
SUM(PID=2) P2,
SUM(PID=3) P3
FROM
sales
LEFT JOIN
user
ON
user.UID = sales.UID
GROUP BY
sales.UID
HAVING
P1+P2+P3 >= 3
ORDER BY
P1 DESC, P2 DESC, P3 DESC;
and here is the sqlfiddle example that shows it in action - http://sqlfiddle.com/#!2/d3405/8

Removing Duplicated Entries: Delete a entry that has 2 the same column

i have this table called bag:
+--------+----------+---------+----------+
| bag_id | chara_id | item_id | item_qty |
+--------+----------+---------+----------+
| 1 | 1 | 2 | 22 |
| 2 | 1 | 1 | 55 |
| 3 | 3 | 1 | 2 |
| 6 | 3 | 4 | 2 |
| 7 | 4 | 4 | 2 |
| 8 | 5 | 4 | 2 |
| 9 | 6 | 4 | 2 |
| 10 | 1 | 5 | 1 |
| 11 | 1 | 2 | 1 |
| 12 | 1 | 2 | 1 |
| 13 | 1 | 2 | 1 |
| 14 | 1 | 8 | 1 |
| 15 | 1 | 6 | 1 |
| 16 | 1 | 8 | 1 |
| 17 | 1 | 6 | 1 |
+--------+----------+---------+----------+
the relationship goes as 1 chara = many item
now i dont want 1 chara = many duplicated item.
how can i make a query that delete's the duplicated values?
like chara_id: 1 has 3 duplicated item_id: 2
i want to delete the other 2.
Not the best way to do it. But the below should definetly work:
Delete from Bag
where bag_id
not in (
select min(bag_id) from bag a,
(select chara_id, item_id
from bag group by chara_id, item_id
having count(*) > 1) b
where a.chara_id = b.chara_id and a.item_id = b.item_id
UNION
select bag_id from bag a,
(select chara_id, item_id
from bag group by chara_id, item_id
having count(*) = 1) b
where a.chara_id = b.chara_id and a.item_id = b.item_id
)
You can simply join table bag with a subquery which gets the minimum bag_id for every combination of chara_ID and item_ID. Records that have null values on any fields on the subquery are the records that will be deleted.
DELETE a
FROM bag a
LEFT JOIN
(
SELECT chara_ID, item_ID, MIN(bag_ID) min_ID
FROM bag
GROUP BY chara_ID, item_ID
) b ON a.bag_ID = b.min_ID AND
a.chara_ID = b.chara_ID AND
a.item_ID = b.item_ID
WHERE b.min_ID IS NULL
SQLFiddle Demo

find the three most sold products every day php mysql

I want to find the three most sold products every day and
show them together with number of sales.
However if there are more than one product sharing the same
number of sales I just want to tell how many products got this
ranking.
I have two tables
Products:
+-----+---------+
| Pid | Product |
+-----+---------+
| 1 | Moon |
| 2 | Sun |
| 3 | Venus |
| 4 | Mars |
+-----+---------+
SalesRows:
+-----+---------+------------+
| Pid | No_sold | Sales_date |
+-----+---------+------------+
| 1 | 1 | 2013-01-01 |
| 2 | 5 | 2013-01-01 |
| 3 | 2 | 2013-01-01 |
| 2 | 2 | 2013-01-01 |
+-----+---------+------------+
Should give:
+------+--------------+-------+
| Rank | Product | Sales |
+------+--------------+-------+
| 1 | Sun | 7 |
| 2 | Venus | 2 |
| 3 | Moon | 1 |
+------+--------------+-------+
However this sales data:
SalesRows:
+-----+---------+------------+
| Pid | No_sold | Sales_date |
+-----+---------+------------+
| 1 | 1 | 2013-01-01 |
| 2 | 5 | 2013-01-01 |
| 3 | 2 | 2013-01-01 |
| 2 | 2 | 2013-01-01 |
| 4 | 1 | 2013-01-01 |
+-----+---------+------------+
Should give:
+------+--------------+-------+
| Rank | Product | Sales |
+------+--------------+-------+
| 1 | Sun | 7 |
| 2 | Venus | 2 |
| 3 | *2 products* | 1 |
+------+--------------+-------+
Any suggestions how to solve this last part?
This query may help you.
SELECT #rownum := #rownum + 1 rownum,
t.*
FROM (SELECT #rownum:=0) r,
(select case when indicator = 1 then Product
else concat( indicator, ' Products') end as Product, sales from (Select *, count(sales) as indicator from (SELECT Product,SUM(No_sold) AS sales FROM SalesRows
JOIN Products ON Products.Pid = SalesRows.Pid
WHERE Sales_date = curdate()
GROUP BY SalesRows.Pid ) a group by sales Order by sales desc) a) t
Try this :
SELECT Product,SUM(No_sold) AS sales FROM SalesRows
LEFT JOIN Products ON Products.Pid = SalesRows.Pid
WHERE Sales_date = '".$today."'
GROUP BY Pid

Categories