mySQL Sum Production_Needed Group BY Part_ID - mysql

Want to generate a result of Open orders where Production is needed. At issue is each part may have more than one open order. With the GROUP BY my code gives me only one order but does give me the total Production_Needed (which is also a negative in value for orders with enough inventory).
Does my SUM(...) as Production_Needed need to be in the WHERE ?
Thanks,
SELECT part.part_ID AS Part_Part_ID,
part.Inventory, part.part_number,
ord.part_id AS Order_Part_ID,
ord.order_type, ord.quantity_ordered, ord.quantity_shipped,
SUM(ord.quantity_ordered - ord.quantity_shipped - part.Inventory) AS Production_Needed
FROM production_orders ord
JOIN production_part part ON ord.part_ID = part.part_ID
WHERE ord.is_Active = True AND ord.order_type = 0
GROUP BY Order_Part_ID
ORDER BY part.part_number ASC
Data Production_Part part
Part_ID
Part_Inventory
Part_Number
1
12500
97-528
2
0
FC2569
3
1000
39367
Data Production_Orders Ord
Order_Part_ID
Order_Type
Quantity_Ordered
Quantity_Shipped
1
0
8000
0
2
0
1000
500
2
0
1000
0
3
1
10
0
Desired Result - Only Parts that need production
Part_ID
Quantity_Ordered
Quantity_Shipped
2
1000
500
2
1000
0

Untested: need a sampled data set and structure for testing:
This creates an inline view and totals the inventory order amounts then stubtracts it from the inventory to determine if there is a production needed to fulfil open orders. I'd have to use some additional analytical functions if we needed to do this on an order by order basis however; or join these results back into the orders...
--Show parts which lack inventory to fullfill outstanding open orders.
SELECT
P.Part_ID as Part_Part_ID
, P.Inventory
, P.Part_Number
, O.Part_ID as Order_Part_ID
, UnDel_Units-coalesce(P.Inventory,0) as Production_Needed --use coalesce incase no part record exists for some reason.
FROM Production_Part P
RIGHT JOIN ( --use right join just incase part record doesn't exist for some reason
SELECT part_ID, SUM(quantity_ordered-quantity_shipped) as UnDel_Units
FROM PRODUCTION_ORDERS
WHERE IS_ACTIVE=TRUE
and ORDER_TYPE=0
GROUP BY PART_ID) O --derived table "O" for orders showing sum ottal by part of units undelivered
on O.Part_ID=P.Part_ID
WHERE UnDel_Units > coalesce(P.Inventory,0)
-- If inventory is > undelivered units for the part, ignore as additional production isn't needed

Related

Selecting rows until a column value isn't the same

SELECT product.productID
, product.Name
, product.date
, product.status
FROM product
INNER JOIN shelf ON product.sheldID=shelf.shelfID
WHERE product.weekID = $ID
AND product.date < '$day'
OR (product.date = '$day' AND shelf.expire <= '$time' )
ORDER BY concat(product.date,shelf.expire)
I am trying to stop the SQL statement at a specific value e.g. bad.
I have tried using max-date, but am finding it hard as am making the time stamp in the query. (Combining date/time)
This example table shows that 3 results should be returned and if the status "bad" was the first result than no results should be returned. (They are ordered by date and time).
ProductID Date status
1 2017-03-27 Good
2 2017-03-27 Good
3 2017-03-26 Good
4 2017-03-25 Bad
5 2017-03-25 Good
Think I may have fixed it, I added this to my while loop.
The query gives the results in order by present to past using date and time, this while loop checks if the column of that row is equal to 'bad' if it is does something (might be able to use an array to fill it up with data). If not than the loop is broken.
I know it doesn't seem ideal but it works lol
while ($row = mysqli_fetch_assoc($result)) {
if ($row['status'] == "bad") {
$counter += 1;
}
else{
break;}
I will provide an answer just with your output as if it was just one table. It will give you the main ideia in how to solve your problem.
Basically I created a column called ord that will work as a row_number (MySql doesn't support it yet AFAIK). Then I got the minimum ord value for a bad status then I get everything from the data where ord is less than that.
select y.*
from (select ProductID, dt, status, #rw:=#rw+1 ord
from product, (select #rw:=0) a
order by dt desc) y
where y.ord < (select min(ord) ord
from (select ProductID, status, #rin:=#rin+1 ord
from product, (select #rin:=0) a
order by dt desc) x
where status = 'Bad');
Result will be:
ProductID dt status ord
-------------------------------------
1 2017-03-27 Good 1
2 2017-03-27 Good 2
3 2017-03-26 Good 3
Also tested with the use case where the Bad status is the first result, no results will be returned.
See it working here: http://sqlfiddle.com/#!9/28dda/1

Ignore columns in MySQL query result with null values

I have a MySql table as,
Name Month Salary
=======================================
A Salary_Month_Sept 15000
A Salary_Month_Oct 0
B Salary_Month_Sept 12000
B Salary_Month_Oct 0
C Salary_Month_Sept 13000
C Salary_Month_Oct 0
and I am querying that table as
select Name,
max(IF(Month = 'Salary_Month_Sept', Salary, 0)) AS 'Salary_Month_Sept',
max(IF(Month = 'Salary_Month_Oct', Salary, 0)) AS 'Salary_Month_Oct'
from myTable
Which returns the query result as
Name Salary_Month_Sept Salary_Month_Oct
=============================================
A 15000 0
B 12000 0
C 17000 0
How can i ignore the column containing only zero or null values from the above query result.
Don't use *. Name columns you want to have. The query is not a crystal ball. It doesn't know in front if there will be data for the column. To do something like that you need 2 queries, assuming the salaries are only positive:
Select sum(salary_sept), sum(salary_oct), ... for the condition you need.
Create second select only for columns returning sum bigger than zero.
The SQL has no time machine, sorry. You have to do your work yourself.

query optimization for mysql

I have the following query which takes about 28 seconds on my machine. I would like to optimize it and know if there is any way to make it faster by creating some indexes.
select rr1.person_id as person_id, rr1.t1_value, rr2.t0_value
from (select r1.person_id, avg(r1.avg_normalized_value1) as t1_value
from (select ma1.person_id, mn1.store_name, avg(mn1.normalized_value) as avg_normalized_value1
from matrix_report1 ma1, matrix_normalized_notes mn1
where ma1.final_value = 1
and (mn1.normalized_value != 0.2
and mn1.normalized_value != 0.0 )
and ma1.user_id = mn1.user_id
and ma1.request_id = mn1.request_id
and ma1.request_id = 4 group by ma1.person_id, mn1.store_name) r1
group by r1.person_id) rr1
,(select r2.person_id, avg(r2.avg_normalized_value) as t0_value
from (select ma.person_id, mn.store_name, avg(mn.normalized_value) as avg_normalized_value
from matrix_report1 ma, matrix_normalized_notes mn
where ma.final_value = 0 and (mn.normalized_value != 0.2 and mn.normalized_value != 0.0 )
and ma.user_id = mn.user_id
and ma.request_id = mn.request_id
and ma.request_id = 4
group by ma.person_id, mn.store_name) r2
group by r2.person_id) rr2
where rr1.person_id = rr2.person_id
Basically, it aggregates data depending on the request_id and final_value (0 or 1). Is there a way to simplify it for optimization? And it would be nice to know which columns should be indexed. I created an index on user_id and request_id, but it doesn't help much.
There are about 4907424 rows on matrix_report1 and 335740 rows on matrix_normalized_notes table. These tables will grow as we have more requests.
First, the others are right about knowing better how to format your samples. Also, trying to explain in plain language what you are trying to do is also a benefit. With sample data and sample result expectations is even better.
However, that said, I think it can be significantly simplified. Your queries are almost completely identical with the exception of the one field of "final_value" = 1 or 0 respectively. Since each query will result in 1 record per "person_id", you can just do the average based on a CASE/WHEN AND remove the rest.
To help optimize the query, your matrix_report1 table should have an index on ( request_id, final_value, user_id ). Your matrix_normalized_notes table should have an index on ( request_id, user_id, store_name, normalized_value ).
Since your outer query is doing the average based on an per stores averages, you do need to keep it nested. The following should help.
SELECT
r1.person_id,
avg(r1.ANV1) as t1_value,
avg(r1.ANV0) as t0_value
from
( select
ma1.person_id,
mn1.store_name,
avg( case when ma1.final_value = 1
then mn1.normalized_value end ) as ANV1,
avg( case when ma1.final_value = 0
then mn1.normalized_value end ) as ANV0
from
matrix_report1 ma1
JOIN matrix_normalized_notes mn1
ON ma1.request_id = mn1.request_id
AND ma1.user_id = mn1.user_id
AND NOT mn1.normalized_value in ( 0.0, 0.2 )
where
ma1.request_id = 4
AND ma1.final_Value in ( 0, 1 )
group by
ma1.person_id,
mn1.store_name) r1
group by
r1.person_id
Notice the inner query is pulling all transactions for the final value as either a zero OR one. But then, the AVG is based on a case/when of the respective value for the normalized value. When the condition is NOT the 1 or 0 respectively, the result is NULL and is thus not considered when the average is computed.
So at this point, it is grouped on a per-person basis already with each store and Avg1 and Avg0 already set. Now, roll these values up directly per person regardless of the store. Again, NULL values should not be considered as part of the average computation. So, if Store "A" doesn't have a value in the Avg1, it should not skew the results. Similarly if Store "B" doesnt have a value in Avg0 result.

MySQL if condition null

I am having database columns
table name:
sales
trans_details
Initially data will be inserted into sales lateron when quantity dispatched trans_details table get updated
columns in sales
total_quantity
e.t.c
columns in trans_details
ordered_quantity
dispatched_quantity
pending_quantity
e.t.c
i want to display all the values:
- ordered_quantity
- dispatched_quantity
- pending_quantity
SELECT
IF(trans.ordered_quantity!='',trans.ordered_quantity,(sorder.total_quantity)) AS quantity,
IF(trans.dispatched!='',trans.dispatched,0) AS today_dispatched_qty,
IF(trans.dispatched!='',trans.dispatched,0) AS dis_qty,
IF(trans.Pending_quantity!='',trans.Pending_quantity,sorder.total_quantity) AS pending_qty
FROM
sales as sorder
LEFT OUTER JOIN trans_details as trans
the query is working fine but when the quantity fully dispatched it should '0' but right now it is showing total_quantity... and when i replace sorder.total_quantity with '0' in this condition IF(trans.Pending_quantity='0',trans.Pending_quantity,sorder.total_quantity) AS pending_qty... initially it is showing '0' but it should show the total_quantity...
sample output:
total_quantity..........dispatched_quantity.......pending_quantity
50 45 5
5 5 0
5 0 5
My guess is that you have NULL values in your data. If the issue is NULLs and the data types are numeric, then try this:
SELECT coalesce(trans.ordered_quantity,sorder.total_quantity) AS quantity,
coalesce(trans.dispatched,0) AS today_dispatched_qty,
coalesce(trans.dispatched,0) AS dis_qty,
coalesce(trans.Pending_quantity,sorder.total_quantity) AS pending_qty
If these really are strings, then you need to add in a NULL check. I would encourage you to use case, which is standard SQL, rather than if:
select (case when trans.ordered_quantity is not null and trans.ordered_quantity <> ''
then trans.ordered_quantity
else sorder.total_quantity
end) as quantity,
. . .
And, finally, I am assuming that you just left off the on clause by accident. In any database other than MySQL, you would get a parse error. But, as a good habit, you should always have an on clause when specifying an inner or outer join.

MySQL compare two values on same table

I'm trying to compare two values in the same table, and check if there is a difference.
Right now, I have 1485 records in the cms_statistics_pages table, but when the query below:
SELECT
cp.identifier,
COUNT(csp1.statID) AS hits,
COUNT(csp2.statID) AS hits_yesterday,
IF(COUNT(csp1.statID)>COUNT(csp2.statID),1,0) AS growth
FROM cms_pages cp
LEFT JOIN cms_statistics_pages csp1
ON csp1.pageID = cp.pageID
AND DATE(csp1.datetime) = '2012-07-20'
LEFT JOIN cms_statistics_pages csp2
ON csp2.pageID = cp.pageID
AND DATE(csp2.datetime) = '2012-07-19'
GROUP BY cp.identifier
..is fired, I get these results:
identifier hits hits_yesterday growth
index 13395 13395 0
siden-er-under-opdatering 638 638 0
vores-historie 0 3 0
Which is not correct for my purpose. Then if I change:
AND DATE(csp1.datetime) = '2012-07-20'
to a date that will match no records
AND DATE(csp1.datetime) = '2012-07-21'
My result now looks like this:
identifier hits hits_yesterday growth
index 0 141 0
siden-er-under-opdatering 0 29 0
vores-historie 0 3 0
Now the hits are correct, so I'm wondering if the query counts the records multiple times when both the joins contains some data.
Example data from cms_pages:
pageID sectionID templateID identifier default title exclude_title
1 1 1 index 1 Welcome to SiteTech Framework 2012
Example data from cms_statistics_pages:
statID frontend backend pageID sectionID panel datetime
1 0 1 34 6 admin 2012-07-17 12:34:14
I came across this post which provides a more advanced way to count across multiple tables, this may prevent the query from counting the same record multiple times. Haven't tried it myself - https://discussion.dreamhost.com/thread-9112.html
So I've been messing around a bit with the query, and found a solution which includes left joins and sub queries. My query now looks like:
SELECT
cp.identifier,
now.hits AS hits,
yd.hits AS hits_yesterday,
IF(now.hits>yd.hits,1,0) AS growth
FROM cms_pages AS cp
LEFT JOIN
(
SELECT
pageID,
COUNT(pageID) AS hits
FROM cms_statistics_pages
WHERE DATE(datetime) = '2012-07-20'
GROUP BY pageID
) now
ON now.pageID = cp.pageID
LEFT JOIN
(
SELECT pageID,
COUNT(pageID) AS hits
FROM cms_statistics_pages
WHERE DATE(datetime) = '2012-07-19'
GROUP BY pageID
) yd
ON yd.pageID = cp.pageID
Which gave me this correct result!:
identifier hits hits_yesterday growth
index 95 141 0
siden-er-under-opdatering 22 29 0
vores-historie NULL 3 0