I have a calculation I am trying to run in the database rather than in php but I cannot get the right result out of it. It uses CASE and SUM because the calculations differ if there is a conversion factor involved.
The saved_total column is the correct total which is a stored value for comparison. The mysql_cost and mysql_total_cost columns are being calculated from the 'commodity_price' table and should match these - but are incorrect.
If I add a grouping of 'ri.preset_val' this gives me 4 rows - and the total of each pair of mysql_total_cost and mysql_cost columns would be correct if added together! (2nd table in snippet).
Tearing the little hair I have left out!
There is a Fiddle
This is the query:
SELECT ri.recipe_id,rnr.recipe_name,rnr.qty_percentage, sum(ri.cost) as saved_total,
CASE
WHEN ri.quantity_unit=3 && ri.type='uom' THEN SUM(ROUND(
cp.cost*ri.qty
,2))
WHEN ri.type='auom' THEN SUM(ROUND(
(cp.cost / 1000 * cau.conversion_factor *ri.qty)
,2))
ELSE ROUND(SUM(
(cp.cost / 1000 * ri.qty * ri.preset_val))
,2) END AS mysql_total_cost,
CASE
WHEN ri.quantity_unit=3 && ri.type='uom' THEN ROUND(SUM(
rnr.qty_percentage
*
(cp.cost*ri.qty)
*.01)
,2)
WHEN ri.type='auom' THEN ROUND(SUM(
rnr.qty_percentage
*
(cp.cost / 1000 * cau.conversion_factor *ri.qty)
*.01
),2)
ELSE ROUND(SUM(
rnr.qty_percentage
*
(cp.cost / 1000 * ri.qty * ri.preset_val)*.01)
,2) END AS mysql_cost
FROM requisition_nested_recipe rnr
LEFT JOIN recipe_ingredient ri ON ri.recipe_id=rnr.recipe_id
LEFT JOIN commodity_price cp ON ri.price_id = cp.commodity_price_id
LEFT JOIN commodity_additional_units cau ON ri.cau_id = cau.cau_id
WHERE rnr.requisition_id=1 AND ri.recipe_id=rnr.recipe_id
GROUP BY ri.recipe_id
This is the ouput:
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/><table class="table">
<tbody><tr><th>recipe_name</th><th>qty_percentage</th><th>saved_total</th><th>mysql_total_cost</th><th>mysql_cost</th></tr>
<tr><td>Brioche</td><td>33.33</td><td>1.4</td><td>1.03</td><td>0.34</td></tr>
<tr><td>Cheesecake Cream</td><td>66.67</td><td>0.95</td><td>0.94</td><td>0.63</td></tr></tbody></table><table class="table"><tbody><tr><th>recipe_name</th><th>qty_percentage</th><th>saved_total</th><th>mysql_total_cost</th><th>mysql_cost</th></tr><tr><td>Brioche</td><td>33.33</td><td>1.01</td><td>1.01</td><td>0.34</td></tr><tr><td>Brioche</td><td>33.33</td><td>0.39</td><td>0.39</td><td>0.13</td></tr><tr><td>Cheesecake Cream</td><td>66.67</td><td>0.87</td><td>0.87</td><td>0.58</td></tr><tr><td>Cheesecake Cream</td><td>66.67</td><td>0.08</td><td>0.08</td><td>0.05</td></tr></tbody></table>
So, to explain a little further, we have 2 recipes in the nested_recipe table that we need to calculate the cost of x % of (qty_percentage). Each ingredient is stored in the recipe_ingredient table. The prices of the commodities (ingredients) are stored in the commodity_price table. To complicate things some of the commodities are in different units of measure that require a conversion - which is where the commodity_additional_units table comes into play.
Note: The cost column in recipe_ingredient table is a stored value. We need to calculate it from the cost (effectively a basecost) of the commodity stored in the commodity_price table.
requisition_nested_recipe table
+----------------+-----------+------------------+----------------+
| requisition_id | recipe_id | recipe_name | qty_percentage |
+----------------+-----------+------------------+----------------+
| 1 | 3138 | Brioche | 33.33 |
| 1 | 3140 | Cheesecake Cream | 66.67 |
+----------------+-----------+------------------+----------------+
recipe_ingredient table
+-----------+--------------+--------+------+----------+--------+------------+------+
| recipe_id | commodity_id | cau_id | type | price_id | qty | preset_val | cost |
+-----------+--------------+--------+------+----------+--------+------------+------+
| 3138 | 10000012 | 0 | uom | 2152 | 350.00 | 1 | 0.27 |
| 3138 | 450526 | 0 | uom | 605 | 5.00 | 1 | 0.00 |
| 3138 | 450644 | 0 | uom | 619 | 35.00 | 1 | 0.06 |
| 3138 | 450908 | 0 | uom | 718 | 7.00 | 1 | 0.10 |
| 3138 | 300160 | 201 | auom | 499 | 3.00 | 3 | 0.39 |
| 3138 | 300021 | 0 | uom | 469 | 170.00 | 1 | 0.58 |
| 3140 | 300103 | 0 | uom | 485 | 100.00 | 1 | 0.40 |
| 3140 | 450644 | 0 | uom | 619 | 10.00 | 1 | 0.02 |
| 3140 | 450741 | 0 | uom | 629 | 0.50 | 5 | 0.08 |
| 3140 | 300104 | 0 | uom | 486 | 150.00 | 1 | 0.45 |
+-----------+--------------+--------+------+----------+--------+------------+------+
commodity_price table
+--------------------+--------------+-------------+-------+
| commodity_price_id | commodity_id | currency_id | cost |
+--------------------+--------------+-------------+-------+
| 469 | 300021 | 1 | 3.40 |
| 485 | 300103 | 1 | 4.00 |
| 486 | 300104 | 1 | 3.00 |
| 499 | 300160 | 1 | 2.25 |
| 605 | 450526 | 1 | 0.39 |
| 619 | 450644 | 1 | 1.60 |
| 629 | 450741 | 1 | 31.00 |
| 718 | 450908 | 1 | 14.83 |
| 1335 | 300021 | 2 | 4.08 |
| 1351 | 300103 | 2 | 4.80 |
| 1352 | 300104 | 2 | 3.60 |
| 1365 | 300160 | 2 | 2.70 |
| 1471 | 450526 | 2 | 0.47 |
| 1485 | 450644 | 2 | 1.92 |
| 1495 | 450741 | 2 | 37.20 |
| 1584 | 450908 | 2 | 17.80 |
| 2152 | 10000012 | 1 | 0.77 |
+--------------------+--------------+-------------+-------+
Commodity_additional_units table
+--------+--------------+------+-------------------+
| cau_id | commodity_id | auom | conversion_factor |
+--------+--------------+------+-------------------+
| 201 | 300160 | 3 | 58.00000 |
+--------+--------------+------+-------------------+
JOIN explodes the number of rows, then the SUM is done on this temp table; finally the GROUP BY shrinks the data back down.
This leads to SUM and COUNT to be bigger than they should be.
The 'fix' is to us the minimum number of JOINs when computing each aggregate. This may involve multiple subqueries.
Related
I have two mysql tables. The two tables with the sample data are as follows.
select * from stock;
+----------+----------+--------+---------+-------------------+---------------+-------------+---------------------+
| stock_id | qty_type | qty | item_id | stock_location_id | stock_type_id | purchase_id | created_date |
+----------+----------+--------+---------+-------------------+---------------+-------------+---------------------+
| 48 | v | 44.00 | 1 | 1 | 1 | 38 | 2022-05-16 14:27:19 |
| 49 | v | 8.00 | 263 | 1 | 1 | 38 | 2022-05-16 14:27:19 |
| 50 | a | 6.00 | 1 | 1 | 1 | 39 | 2022-05-16 14:30:04 |
| 51 | a | 4.00 | 263 | 1 | 1 | 39 | 2022-05-16 14:30:04 |
| 56 | a | 28.00 | 1 | 1 | 1 | 41 | 2022-05-16 14:51:59 |
| 57 | a | 57.00 | 263 | 1 | 1 | 41 | 2022-05-16 14:51:59 |
| 58 | a | 6.00 | 264 | 1 | 1 | 41 | 2022-05-16 14:51:59 |
| 59 | a | 19.00 | 301 | 1 | 1 | 41 | 2022-05-16 14:51:59 |
| 64 | a | 15.00 | 263 | 1 | 5 | 0 | 2022-05-18 17:23:37 |
| 65 | a | 546.00 | 264 | 1 | 5 | 0 | 2022-05-18 17:23:37 |
| 66 | a | 15.00 | 263 | 1 | 5 | 0 | 2022-05-18 17:24:21 |
| 67 | a | 546.00 | 264 | 1 | 5 | 0 | 2022-05-18 17:24:21 |
| 72 | v | 20.00 | 720 | 1 | 1 | 44 | 2022-05-24 09:24:43 |
| 73 | v | 2.00 | 729 | 1 | 1 | 44 | 2022-05-24 09:24:43 |
+----------+----------+--------+---------+-------------------+---------------+-------------+---------------------+
select * from sales;
+----------+---------+----------+-----------+
| sales_id | item_id | quantity | basket_id |
+----------+---------+----------+-----------+
| 7 | 1 | 20.00 | 4 |
| 8 | 263 | 3.00 | 4 |
| 9 | 1 | 2.00 | 5 |
| 10 | 263 | 4.00 | 5 |
| 11 | 264 | 6.00 | 5 |
| 12 | 301 | 1.00 | 5 |
+----------+---------+----------+-----------+
By this I want to build up a update query. This should deduct the quantity of the items in the sales table from the stock table. If such a query can be created in mysql it should be updated in ascending order on the stock_id in the stock table.
If such an update query can be built, based on the data in the two tables above, I expect the result to be as follows.
select stock_id, qty_type, qty, item_id from stock where qty_type = 'a';
+----------+----------+--------+---------+
| stock_id | qty_type | qty | item_id |
+----------+----------+--------+---------+
| 50 | a | 0.00 | 1 | -- clear by sales
| 51 | a | 0.00 | 263 | -- clear by sales
| 56 | a | 12.00 | 1 | -- deduct qty by sales
| 57 | a | 54.00 | 263 | -- deduct qty by sales
| 58 | a | 0.00 | 264 | -- clear by sales
| 59 | a | 18.00 | 301 | -- deduct qty by sales
| 64 | a | 15.00 | 263 |
| 65 | a | 546.00 | 264 |
| 66 | a | 15.00 | 263 |
| 67 | a | 546.00 | 264 |
+----------+----------+--------+---------+
Any help would be highly appreciated.
Here is my understanding of the problem:
According to your stock table, there are 06 quantity in hand of item_id #1
+----------+----------+-------+---------+
| stock_id | qty_type | qty | item_id |
+----------+----------+-------+---------+
| 50 | a | 6.00 | 1 |
+----------+----------+-------+---------+
Then again a new stock comes in and new entry is made in stock table. For example, another 28 quantity has come in, so the table would look like as follows:
+----------+----------+-------+---------+
| stock_id | qty_type | qty | item_id |
+----------+----------+-------+---------+
| 50 | a | 6.00 | 1 |
| 56 | a | 28.00 | 1 |
+----------+----------+-------+---------+
Now, there are 6 + 28 = 34 quantity in stock. According to your sales data, you have sold twice of item_id #1. As first time 20 items and next time 2 items. Since we have more quantity in stock than sold quantity, so we can do both sales.
As you mentioned in your question, now we have to adjust the sold items from stock in ascending order on the stock_id in the stock table. Of course here you are using the First In First Out (FIFO) method to maintain your stock. This method works in such a way that you have to clear stock which has come first.
Now it would not be a very simple SQL which can update the stock in hand, however this is my attempt.
INSERT INTO stock (stock_id, qty)
SELECT stock_id
, newqty
FROM (
SELECT
stock_id
, #sales := IF(#prev = k.item_id, #sales, sold) as sales
, IF(qty <= #sales, 0, qty - #sales) as newqty
, #sales := IF(#sales >= qty, #sales - qty, 0)
, #prev := k.item_id as item
FROM stock k
JOIN (
SELECT item_id
, sum(quantity) as sold
FROM sales
GROUP BY item_id
) s ON k.item_id = s.item_id AND qty_type = 'a'
JOIN (SELECT #prev:=null, #sales:=0) init
ORDER BY k.item_id, stock_id
) calc
ON DUPLICATE KEY UPDATE
qty = VALUES(qty);
My query can only be run once for a set of sales data as each time it reduces the stock and updates the stock table (as you requested). Not the best method as it means storing derived data.
The following is the result of running the above query one at a time each time data is added to the sales table.
Starting Stock
select * from stock;
+----------+----------+-------+---------+-------------------+---------------+-------------+
| stock_id | qty_type | qty | item_id | stock_location_id | stock_type_id | purchase_id |
+----------+----------+-------+---------+-------------------+---------------+-------------+
| 1 | a | 6.00 | 1 | 1 | 5 | 0 |
| 2 | a | 28.00 | 1 | 1 | 5 | 0 |
+----------+----------+-------+---------+-------------------+---------------+-------------+
Result 01 - After 1st sale
select * from sales;
+----------+---------+----------+-----------+
| sales_id | item_id | quantity | basket_id |
+----------+---------+----------+-----------+
| 1 | 1 | 20.00 | 1 |
+----------+---------+----------+-----------+
select * from stock;
+----------+----------+-------+---------+-------------------+---------------+-------------+
| stock_id | qty_type | qty | item_id | stock_location_id | stock_type_id | purchase_id |
+----------+----------+-------+---------+-------------------+---------------+-------------+
| 1 | a | 0.00 | 1 | 1 | 5 | 0 |
| 2 | a | 14.00 | 1 | 1 | 5 | 0 |
+----------+----------+-------+---------+-------------------+---------------+-------------+
Result 02 - After 2nd sale
select * from sales;
+----------+---------+----------+-----------+
| sales_id | item_id | quantity | basket_id |
+----------+---------+----------+-----------+
| 1 | 1 | 20.00 | 1 |
| 2 | 1 | 2.00 | 2 |
+----------+---------+----------+-----------+
select * from stock;
+----------+----------+-------+---------+-------------------+---------------+-------------+
| stock_id | qty_type | qty | item_id | stock_location_id | stock_type_id | purchase_id |
+----------+----------+-------+---------+-------------------+---------------+-------------+
| 1 | a | 0.00 | 1 | 1 | 5 | 0 |
| 2 | a | 12.00 | 1 | 1 | 5 | 0 |
+----------+----------+-------+---------+-------------------+---------------+-------------+
I have a MySQL database with vehicles, issued_fuel and mileage data (vs issued fuel) and want to get the following desired output.
Desired Output
I want to get results including above related data as follows :
+---------------+------------+------------+---------+----------+
| registered_no | issue_date | date | mileage | fuel_qty |
+---------------+------------+------------+---------+----------+
| SP KR-3503 | 2021-02-22 | null | null | 40 |
| SP KR-3503 | 2021-02-26 | null | null | 30 |
| null | 2021-03-03 | null | null | 40 |
| null | 2021-03-15 | null | null | 45 |
| SP KR-3503 | 2021-03-18 | null | null | 40 |
| null | 2021-03-25 | null | null | 45 |
| null | 2021-04-04 | null | null | 35 |
| SP KE-6794 | 2021-04-25 | 2021-04-25 | 150 | 40 |
+---------------+------------+------------+---------+----------+
Because the table "tbl_trip_details" includes only one mileage (150km) for vehicle_no "SP KE-6794 for the date 2021-04-25.
My tables as follows :
tbl_vehicle
+------------+---------------+--------+
| vehicle_id | registered_no | status |
+------------+---------------+--------+
| 1 | SP KR-3503 | 1 |
| 2 | SP KE-6794 | 1 |
+------------+---------------+--------+
tbl_trip_details
+---------+------------+------------+---------+--------+
| trip_id | vehicle_id | date | mileage | status |
+---------+------------+------------+---------+--------+
| 1 | 1 | 2021-04-25 | 125 | 1 |
| 2 | 1 | 2021-04-26 | 100 | 1 |
| 3 | 2 | 2021-04-25 | 150 | 1 |
+---------+------------+------------+---------+--------+
tbl_direct_fuel
+----------------+---------+------------+
| direct_fuel_id | vehicle | issue_date |
+----------------+---------+------------+
| 1 | 1 | 2021-02-22 |
| 2 | 1 | 2021-02-26 |
| 3 | 3 | 2021-03-03 |
| 4 | 3 | 2021-03-15 |
| 5 | 1 | 2021-03-18 |
| 6 | 3 | 2021-03-25 |
| 7 | 3 | 2021-04-04 |
| 8 | 2 | 2021-04-25 |
+----------------+---------+------------+
tbl_direct_fuel_details
+-----------------------------+----------------+------+----------+
| tbl_deirect_fuel_details_id | direct_fuel_id | item | fuel_qty |
+-----------------------------+----------------+------+----------+
| 1 | 1 | 1 | 40 |
| 2 | 2 | 1 | 30 |
| 3 | 3 | 1 | 40 |
| 4 | 4 | 1 | 45 |
| 5 | 5 | 1 | 40 |
| 6 | 6 | 1 | 45 |
| 7 | 7 | 1 | 35 |
| 8 | 8 | 1 | 40 |
+-----------------------------+----------------+------+----------+
I used the following query
select tv.registered_no, df.issue_date, td.date, td.mileage, df.fuel_qty
from tbl_trip_details trip
left join tbl_vehicle tv on tv.vehicle_id=trip.vehicle_id
join (select tbl_direct_fuel.direct_fuel_id, tbl_vehicle.registered_no, tbl_direct_fuel.vehicle, tbl_direct_fuel.issue_date, item, tbl_direct_fuel_details.fuel_qty, tbl_direct_fuel_details.fuel_price
from tbl_direct_fuel_details
left join tbl_direct_fuel on tbl_direct_fuel_details.direct_fuel_id = tbl_direct_fuel.direct_fuel_id
join tbl_vehicle on tbl_vehicle.vehicle_id = tbl_direct_fuel.vehicle
where tbl_direct_fuel.status=1
order by tbl_vehicle.registered_no
) AS df on df.vehicle = tv.vehicle_id
join (select tbl_trip_details.trip_id, tbl_vehicle.registered_no, tbl_trip_details.vehicle_id, tbl_trip_details.date, tbl_trip_details.mileage
from tbl_trip_details
left join tbl_vehicle on tbl_vehicle.vehicle_id = tbl_trip_details.vehicle_id
where tbl_trip_details.status=1
order by tbl_vehicle.registered_no) AS td on td.vehicle_id = tv.vehicle_id
Since the date & mileage are repeated for other records and didn't get the expected result. So the query outs the following output:
+---------------+------------+------------+---------+----------+
| registered_no | issue_date | date | mileage | fuel_qty |
+---------------+------------+------------+---------+----------+
| SP KR-3503 | 2021-02-22 | 2021-04-25 | 150 | 40 |
| SP KR-3503 | 2021-02-26 | 2021-04-25 | 150 | 30 |
| null | 2021-03-03 | 2021-04-25 | 150 | 40 |
| null | 2021-03-15 | 2021-04-25 | 150 | 45 |
| SP KR-3503 | 2021-03-18 | 2021-04-25 | 150 | 40 |
| null | 2021-03-25 | 2021-04-25 | 150 | 45 |
| null | 2021-04-04 | 2021-04-25 | 150 | 35 |
| SP KE-6794 | 2021-04-25 | 2021-04-25 | 150 | 40 |
+---------------+------------+------------+---------+----------+
What may be going wrong in my query ? Can anyone help ?
Try this query:
SELECT tv.registered_no, tdf.issue_date, ttd.date, ttd.mileage, tdfd.fuel_qty
FROM tbl_direct_fuel tdf
LEFT JOIN tbl_vehicle tv
ON tdf.vehicle=tv.vehicle_id
LEFT JOIN tbl_trip_details ttd
ON tdf.vehicle=ttd.vehicle_id
AND tdf.issue_date=ttd.date
LEFT JOIN tbl_direct_fuel_details tdfd
ON tdf.direct_fuel_id=tdfd.direct_fuel_id;
Demo fiddle
Rather than having two separate sub-queries, I try to directly get the result with a bunch of LEFT JOINs. From what I can see in the updated expected result, tbl_direct_fuel is enough to be the reference table for all the others. I's just a matter of figuring the correct ON condition.
Also, I mentioned about the missing tbl_direct_fuel.status and tbl_direct_fuel_details.fuel_price from the sample data. I'm not concerned about tbl_direct_fuel_details.fuel_price in particular because it wasn't included in the end SELECT result however, tbl_direct_fuel.status was being used in WHERE might have some impact. But after constructing the possible query, I assume that in this example, it's not required to include tbl_direct_fuel.status at all. Anyway, that's for you to figure out.
Suppose we have tables resource, item and price:
item
+--------+---------+
| itemId | name |
+--------+---------+
| 2743 | Product |
+--------+---------+
resource
+------------------+-----+----------------+--+
|resourceId | key | value | groupId |
+-----------+-----+----------------+---------+
| 45 | 1 | Client | 3 |
| 46 | 2 | Manufacturer | 3 |
| 69 | 1 | Delivery | 4 |
| 70 | 2 | Collection | 4 |
| 71 | 3 | Assembly | 4 |
| 72 | 4 | Client Request | 4 |
| 73 | 1 | Draft | 5 |
| 74 | 2 | Not Confirmed | 5 |
| 75 | 3 | Confirmed | 5 |
+-----------+-----+----------------+---------+
price
+---------+-----------+--------+----------+
| priceId | serviceId | itemId | price |
+---------+-----------+--------+----------+
| 294 | 4 | 0 | 20.0000 |
| 293 | 3 | 0 | 20.0000 |
| 292 | 2 | 0 | 20.0000 |
| 291 | 1 | 0 | 20.0000 |
| 290 | 1 | 2743 | 18.4000 |
| 288 | 1 | 2738 | 10.0000 |
| 267 | 4 | 2721 | 0.0000 |
| 266 | 3 | 2721 | 0.0000 |
| 265 | 2 | 2721 | 0.0000 |
+---------+-----------+--------+----------+
Rows in table resource with groupId=4 are services. They are refered to via column key from table price (serviceId). As you can see I have default prices for those services (first four rows in price with itemId=0). I need to fetch as many pirce rows as there are services for a given item. If that item doesn't have a price for a service, service's default price should be fetched. For example, the item with id = 2743 has price for service Delivery. For all other services their default prices should be returned. What I need is a result like this:
+---------+-----------+--------+----------+-----------+-----+----------------+---------+
| priceId | serviceId | itemId | price |resourceId | key | value | groupId |
+---------+-----------+--------+----------+-----------+-----+----------------+---------+
| 290 | 1 | 2743 | 18.4000 | 69 | 1 | Delivery | 4 |
| 292 | 2 | NULL | 17.0000 | 70 | 2 | Collection | 4 |
| 293 | 3 | NULL | 13.0000 | 71 | 3 | Assembly | 4 |
| 294 | 4 | NULL | 9.0000 | 72 | 4 | Client Request | 4 |
+---------+-----------+--------+----------+-----------+-----+----------------+---------+
Here is a query I tried. I get as many rows as services, but all of them have have the same price (that of the item)
SELECT *
FROM `price` AS `p`
INNER JOIN `item` ON p.id = item.id
RIGHT JOIN `resource` AS `res` ON 1 = 1
WHERE (res.groupId = 4)
AND (p.itemId = 2743);
select i.itemId, coalesce(p1.price, p0.price)
from item i
cross join price p0
left join price p1
on p1.serviceId = p0.serviceId
and p1.itemId = i.itemId
where i.itemId = 2743
and p0.itemId = 0
I have three tables, mess_stock, mess_voucher, add_grocery.
Mess_stock table is below,
+-----+------------+-----------------+-----------------+--------+---------+---------+------------+----------+
| sno | voucher_id | particular_name | opening_balance | inward | outward | balance | pay_amount | pay_type |
+-----+------------+-----------------+-----------------+--------+---------+---------+------------+----------+
| 49 | 5 | 4 | 100 | 10 | 100 | 10 | 10.00 | 1 |
| 50 | 17 | 5 | 111 | 10 | 20 | 101 | 60.00 | 1 |
| 51 | 7 | 3 | 123 | 2 | 1 | 124 | 300.00 | 1 |
| 52 | 7 | 1 | 123 | 20 | 20 | 123 | 500.00 | 2 |
| 53 | 14 | 8 | 100 | 5 | 95 | 10 | 60.00 | 2 |
+-----+------------+-----------------+-----------------+--------+---------+---------+------------+----------+
Mess_voucher table is below
+------------+--------------+--------------+
| voucher_id | voucher_name | voucher_date |
+------------+--------------+--------------+
| 5 | VG1001 | 2015-02-19 |
| 6 | VG1001 | 2015-02-20 |
| 7 | VG1002 | 2015-02-20 |
| 8 | VG1002 | 2015-02-19 |
| 9 | MS1001 | 2015-02-20 |
| 10 | VG10012 | 2015-02-19 |
| 11 | 0 | 2015-02-23 |
| 12 | 1 | 2015-02-24 |
| 13 | MS1001 | 2015-02-25 |
| 14 | MS1001 | 2015-02-28 |
| 15 | VG1003 | 2015-02-28 |
| 16 | MS1001 | 2015-02-19 |
| 17 | MS1001 | 2015-02-21 |
+------------+--------------+--------------+
Add_grocery table is below
+-----+-----------------+------------------+
| sno | particular_name | particular_price |
+-----+-----------------+------------------+
| 1 | Rice | 25.00 |
| 3 | Mango | 150.00 |
| 4 | Coconut | 22.00 |
| 5 | Banana | 6.00 |
| 6 | Raddish | 12.00 |
| 7 | Apple | 150.00 |
| 8 | Pumkin | 12.00 |
+-----+-----------------+------------------+
I want to group the sum of pay_amount of mess_stock table. I have used the below query
SELECT opening_balance AS ope_stock,
balance AS clo_stock,
SUM(IF(pay_type = 1, pay_amount, 0)) mess_pay,
SUM(IF(pay_type=2, pay_amount, 0)) est_pay
FROM mess_stock;
That works fine. The particular_name is the auto increment id of add_grocery table. I need the inward outward amount total. For example the inward amount 10 means it has to get the particular_price from add_grocery using the particular_name provided in the mess_stock table, similarly I need all the answer. And I want to sort that by date wise. The date of the entry is stored in the mess_voucher table that is connected to mess_stock table.
Try this it will work :
Use Inner Join :
SELECT t2.`particular_name`,t1.`inward`,t1.`outward`,t2.`particular_price`,t3.`voucher_date` from Mess_stock t1 JOIN Add_grocery t2 ON t1.`particular_name`=t2.`sno` JOIN Mess_voucher t3 ON t3.`voucher_id`=t1.`voucher_id` ORDER BY t3.`voucher_date` DESC
Despite spending an hour on this, the solution is eluding me still. I have a complex-ish query that is returning incorrect data for the SUM(). Yet, when I strip it down to the barest form, it outputs the correct data. But why and fix, I cannot figure out.
The Problem
SELECT po.*, SUM( poo.material_qty ) AS total_items_ordered, suppliers.supplier_name
FROM `purchase_orders` po
LEFT JOIN purchase_orders_items poo ON poo.poid = po.poid
LEFT JOIN suppliers ON suppliers.supplier_id = po.supplier_id
LEFT JOIN materials_batch mb ON mb.purchase_order_no = po.poid
WHERE po_status NOT
IN (
'Fulfilled', 'Cancelled'
)
AND batch_status NOT
IN (
'Arrived', 'Cancelled', 'Refused', 'Missing', 'Damaged', 'Completed'
)
GROUP BY po.poid
ORDER BY date_expected ASC
Provides wildly incorrect data for 'total_items_ordered'.
+-------+---------------------+---------------------+-------------+--------+-------------+--------+-----------+---------+----------+--------+----+--------+-----------+---------------------+-----------------------+
| poid | date_raised | date_expected | supplier_id | job_id | job_item_id | ref_no | sub_total | VAT | total | userid | DN | manual | po_status | total_items_ordered | supplier_name |
+-------+---------------------+---------------------+-------------+--------+-------------+--------+-----------+---------+----------+--------+----+--------+-----------+---------------------+-----------------------+
| 15571 | 2014-06-24 13:32:55 | 2014-06-25 00:00:00 | 1 | 0 | 0 | | 14850.10 | 2970.02 | 17820.12 | 1 | | N | Raised | 545 | John Parker & Son Ltd |
| 15572 | 2014-06-24 13:33:26 | 2014-06-25 00:00:00 | 1 | 0 | 0 | | 997.80 | 199.56 | 1197.36 | 1 | | N | Raised | 80 | John Parker & Son Ltd |
+-------+---------------------+---------------------+-------------+--------+-------------+--------+-----------+---------+----------+--------+----+--------+-----------+---------------------+-----------------------+
2 rows in set (0.00 sec)
And yet, when I strip all the complexities out of the query and run the raw SUM(), the value is correct:
mysql> SELECT poid, SUM(material_qty) AS total_items_ordered FROM `purchase_orders_items` GROUP BY poid;
+-------+---------------------+
| poid | total_items_ordered |
+-------+---------------------+
| 15571 | 109 |
| 15572 | 20 |
+-------+---------------------+
2 rows in set (0.00 sec)
Can anyone shed any light on where I'm going wrong here?? I've included all the test table content below just in case you can spot something I've missed. Thank you!
Data Example
mysql> SELECT * FROM purchase_orders;
+-------+---------------------+---------------------+-------------+--------+-------------+--------+-----------+---------+----------+--------+----+--------+-----------+
| poid | date_raised | date_expected | supplier_id | job_id | job_item_id | ref_no | sub_total | VAT | total | userid | DN | manual | po_status |
+-------+---------------------+---------------------+-------------+--------+-------------+--------+-----------+---------+----------+--------+----+--------+-----------+
| 15571 | 2014-06-24 13:32:55 | 2014-06-25 00:00:00 | 1 | 0 | 0 | | 14850.10 | 2970.02 | 17820.12 | 1 | | N | Raised |
| 15572 | 2014-06-24 13:33:26 | 2014-06-25 00:00:00 | 1 | 0 | 0 | | 997.80 | 199.56 | 1197.36 | 1 | | N | Raised |
+-------+---------------------+---------------------+-------------+--------+-------------+--------+-----------+---------+----------+--------+----+--------+-----------+
2 rows in set (0.00 sec)
mysql> SELECT * FROM purchase_orders_items;
+--------+-------+-------------+--------------+----------------+--------------+--------------------------------------------------+
| poi_id | poid | material_id | material_qty | material_price | material_sku | material_name |
+--------+-------+-------------+--------------+----------------+--------------+--------------------------------------------------+
| 1 | 15571 | 2 | 3 | 100.00 | PKS275282 | 406x140 White Universal Beam (S355) |
| 2 | 15571 | 5 | 10 | 17.40 | 118-64-44 | Test Item (S275) |
| 3 | 15571 | 8 | 1 | 9984.50 | 113-64-21 | A really really really big universal beam (S355) |
| 4 | 15571 | 9 | 77 | 10.00 | 12345 | A thing |
| 5 | 15571 | 10 | 18 | 201.20 | 12-34-56 | 102x230 Narrow Beam (S355) |
| 6 | 15572 | 2 | 6 | 100.00 | PKS275282 | 406x140 White Universal Beam (S355) |
| 7 | 15572 | 5 | 9 | 17.40 | 118-64-44 | Test Item (S275) |
| 8 | 15572 | 9 | 4 | 10.00 | 12345 | A thing |
| 9 | 15572 | 10 | 1 | 201.20 | 12-34-56 | 102x230 Narrow Beam (S355) |
+--------+-------+-------------+--------------+----------------+--------------+--------------------------------------------------+
9 rows in set (0.00 sec)
mysql> SELECT * FROM suppliers;
+-------------+-----------------------+--------------------+--------------+---------------------+-------------------+-----------------------+--------------------------+---------------------+----------------------+
| supplier_id | supplier_name | supplier_telephone | supplier_fax | supplier_added_date | supplier_added_by | supplier_last_updated | supplier_last_updated_by | supplier_assessed | supplier_approved_by |
+-------------+-----------------------+--------------------+--------------+---------------------+-------------------+-----------------------+--------------------------+---------------------+----------------------+
| 1 | John Parker & Son Ltd | 01227 783333 | 0800 521932 | 2014-05-04 15:57:43 | 1 | 2014-06-05 16:38:23 | 1 | 2014-05-04 15:57:43 | 2 |
| 2 | Superior Glass Ltd. | 01825 764766 | 01825 767699 | 2014-05-04 17:48:38 | 1 | 2014-06-04 20:14:16 | 1 | 2014-05-04 17:48:38 | 3 |
| 3 | DTS Origins Ltd. | 01283 3283029 | 01928 303494 | 2014-05-04 17:51:57 | 1 | 2014-05-04 17:53:08 | 1 | 2014-05-04 17:51:57 | 2 |
+-------------+-----------------------+--------------------+--------------+---------------------+-------------------+-----------------------+--------------------------+---------------------+----------------------+
3 rows in set (0.00 sec)
mysql> SELECT * FROM materials_batch;
+-------------------+-------+---------------------+-------------------+------------------+-----+---------+------------+-------------+-------------+--------------+
| material_batch_id | poiid | rcvd_date | purchase_order_no | delivery_note_no | qty | rcvd_by | dn_scanned | material_id | supplier_id | batch_status |
+-------------------+-------+---------------------+-------------------+------------------+-----+---------+------------+-------------+-------------+--------------+
| 1 | 1 | 0000-00-00 00:00:00 | 15571 | | 3 | 0 | No | 2 | 1 | Ordered |
| 2 | 2 | 0000-00-00 00:00:00 | 15571 | | 10 | 0 | No | 5 | 1 | Ordered |
| 3 | 3 | 0000-00-00 00:00:00 | 15571 | | 1 | 0 | No | 8 | 1 | Ordered |
| 4 | 4 | 0000-00-00 00:00:00 | 15571 | | 77 | 0 | No | 9 | 1 | Ordered |
| 5 | 5 | 0000-00-00 00:00:00 | 15571 | | 18 | 0 | No | 10 | 1 | Ordered |
| 6 | 6 | 0000-00-00 00:00:00 | 15572 | | 6 | 0 | No | 2 | 1 | Ordered |
| 7 | 7 | 0000-00-00 00:00:00 | 15572 | | 9 | 0 | No | 5 | 1 | Ordered |
| 8 | 8 | 0000-00-00 00:00:00 | 15572 | | 4 | 0 | No | 9 | 1 | Ordered |
| 9 | 9 | 0000-00-00 00:00:00 | 15572 | | 1 | 0 | No | 10 | 1 | Ordered |
+-------------------+-------+---------------------+-------------------+------------------+-----+---------+------------+-------------+-------------+--------------+
The reason for the wrong results should be clear when you leave out the GROUP BY from your query. For each table you JOIN, the number of returned rows is multiplied by the number of rows found by the JOIN.
As the materials_batch table contains multiple entries per order, the resulting total_items_ordered is multiplied by 5 for order number 15571, and its multiplied by 4 for order number 15572.
Try the following:
SELECT
po.*,
(
SELECT SUM(poo.material_qty)
FROM purchase_orders_items poo
WHERE poo.poid = po.poid
) AS total_items_ordered,
suppliers.supplier_name
FROM `purchase_orders` po
LEFT JOIN suppliers ON suppliers.supplier_id = po.supplier_id
LEFT JOIN materials_batch mb ON mb.purchase_order_no = po.poid
WHERE po_status NOT
IN (
'Fulfilled', 'Cancelled'
)
AND batch_status NOT
IN (
'Arrived', 'Cancelled', 'Refused', 'Missing', 'Damaged', 'Completed'
)
GROUP BY po.poid
ORDER BY date_expected ASC