Need help updating table from a select query - mysql

I have the following code that produces a list of order numbers and values...
SELECT
d.`OrderNo`,
SUM(v.`UnitPrice`)
FROM tblverification v
LEFT JOIN tblorderdetailsafter d ON v.`VMainID` = d.`MainID`
GROUP BY d.`OrderNo`;
I need to update a table called matcontctsafter which has an OrderNo field and currently blank InvoiceAmount column that I need the relative SUM(v.UnitPrice) in.
Can anybody help me construct the UPDATE clause?

UPDATE matcontctsafter m
INNER JOIN (
SELECT
d.`OrderNo`,
SUM(v.`UnitPrice`) InvoiceAmount
FROM tblverification v
LEFT JOIN tblorderdetailsafter d ON v.`VMainID` = d.`MainID`
GROUP BY d.`OrderNo`
) sq ON m.OrderNo = sq.OrderNo
SET m.InvoiceAmount = sq.InvoiceAmount;

UPDATE matcontctsafter m SET m.InvoiceAmount = (SELECT
SUM(v.UnitPrice)
FROM tblverification v
LEFT JOIN tblorderdetailsafter d ON v.VMainID = d.MainID
WHERE m.OrderNo = d.OrderNo);

Related

Alternative to Where Exist clause MySQL

I have this select statement that is taking quite a while to run on a larger dataset
select lookup_svcscat_svcscatnew.SVCSCAT_NEW_DESC as svc_type,
enrolid, msclmid, dx1, dx2, dx3,
proc1,msk_cpt_mapping.surg_length_cd as SL_CD,
msk_cpt_mapping.days as day_window,o.svcdate_form, pay,
table_label
from ccaeo190_ky o
left join lookup_svcscat_svcscatnew on o.svcscat = lookup_svcscat_svcscatnew.svcscat
left join msk_cpt_mapping on o.proc1 = msk_cpt_mapping.cpt_code
where EXISTS
(
select 1
from eoc_op_mapping e
where e.msclmid = o.msclmid
and e.enrolid = o.enrolid
and proc1 =27447
)
ORDER BY svcdate_form, msclmid;
I want to return any row in my ccaeo190_ky table that meets the requirements of the where EXISTS clause on table eoc_op_mapping. Is there any way to achieve these results using joins or select statements?
I was thinking something like:
select lookup_svcscat_svcscatnew.SVCSCAT_NEW_DESC as svc_type,
o.enrolid, o.msclmid, dx1, dx2, dx3,
proc1,msk_cpt_mapping.surg_length_cd as SL_CD,
msk_cpt_mapping.days as day_window,o.svcdate_form, pay,
table_label
from ccaeo190_ky o
left join lookup_svcscat_svcscatnew on o.svcscat = lookup_svcscat_svcscatnew.svcscat
left join msk_cpt_mapping on o.proc1 = msk_cpt_mapping.cpt_code
inner join
(select msclmid, SUM(IF(proc1 = 27447,1,0)) AS cpt
from eoc_op_mapping
group by enrolid
HAVING cpt > 0) e
on e.enrolid = o.enrolid
group by o.enrolid;
But I don't know if this is in the right direction
Usually EXISTS performs better than a join.
If you want to try a join, this the equivalent to your WHERE EXISTS:
.......................................................
inner join (
select distinct msclmid, enrolid
from eoc_op_mapping
where proc1 = 27447
) e on e.msclmid = o.msclmid and e.enrolid = o.enrolid
.......................................................
You can remove distinct if there are no duplicate msclmid, enrolid combinations in eoc_op_mapping.

Counting entry in a column MySQL and display counts

I would want to count entries in a column and display the count beside it.
However, I'm clueless on how can I do it.
Desired output:
arrangement_number tray_no rl_type flag(count of occurrence)
------------------ ------- ---- ----
2774818 381001 R 3
2774818 381001 R 3
2774818 381001 L 3
2778470 405128 R 1
2779702 265265 R 2
2779702 265265 R 2
I'm currently trying queries using #variables but I still cant get it right.
each row are unique and I need them not to be grouped.
Update: Expanded Table added source code
Note: I'm currently joining 5 tables now
Actual Query:
SELECT
log.arrangement_number,
header.tray_number,
detail.rl_type,
-- some more fields here
FROM
log
INNER JOIN
header ON log.arrangement_number = header.rxarrangement_number
AND log.production_place_code = header.production_place_code
INNER JOIN
detail ON log.arrangement_number = detail.rxarrangement_number
AND log.production_place_code = detail.production_place_code
INNER JOIN
deliveryperiod ON log.arrangement_number = deliveryperiod.arrangement_number
AND log.production_place_code = deliveryperiod.production_place_code
AND detail.rl_type = deliveryperiod.rl_type
INNER JOIN
calc ON calc.arrangement_number = log.arrangement_number
AND calc.production_place_code = log.production_place_code
AND deliveryperiod.rl_type = calc.rl_type
AND detail.rl_type = calc.rl_type
WHERE
header.status_code IN ('20' , '21')
AND log.process_code = '12'
AND deliveryperiod.process_code_current = '12'
AND deliveryperiod.sub_process_code_current IN ('100' , '105')
AND lot_number = '120131'
ORDER BY log.lot_number , log.sequence_number , deliveryperiod.rl_type DESC
SELECT t1.tray_no,
t2.flag
FROM yourTable
INNER JOIN
(
SELECT tray_no, COUNT(*) AS flag
FROM yourTable
GROUP BY tray_no
) t2
ON t1.tray_no = t2.tray_no
try this...
SELECT tray_no, COUNT(*) 'flag'
FROM table1
GROUP BY tray_no

Update statement with nested joins not working

I need to update multiple records in a table based upon the sum of some values in another table. Here is my query:
UPDATE aallinnot2 c SET c.Energ_Kcal = ( SELECT d.id1, SUM( c.Energ_Kcal)
FROM aaingred a
LEFT JOIN aaweight b ON a.unit = b.uni
LEFT JOIN aallinnot2 c ON a.mfdfsds = c.NDB_No
LEFT JOIN aalinfsds d ON a.fsdsnum = d.id1
WHERE d.own_id =42
GROUP BY id1 )
WHERE c.NDB_No
IN ( SELECT DISTINCT `fsdsnum`
FROM `aaingred`
WHERE `usernum` LIKE '42'
)
MySQL said:
#1093 - You can't specify target table 'c' for update in FROM clause
Unfortunately, I don't know how to get my values without referencing target table 'c'! Is there a workaround for this?
With the crazy table/column names and indecipherable logic, this might be the ugliest query I have ever seen. Congrats. :)
I think the following should work (or this approach). The main problem was untangling the group-by expression-- you need to give the database engine a dataset where each row in the target table is joined to a set that contains the updated value for that row. So here, select the new values in a sub-query, then join that sub-query to the original table.
EDIT Fixed some syntax
UPDATE
(
SELECT d.id1, SUM (c.Energ_Kcal) AS Sum_Energ_Kcal
FROM aaingred a
LEFT JOIN aaweight b ON a.unit = b.uni
LEFT JOIN aallinnot2 c ON a.mfdfsds = c.NDB_No
LEFT JOIN aalinfsds d ON a.fsdsnum = d.id1
WHERE d.own_id =42
GROUP BY id1
) d
,aaingred a, aallinnot2 d
SET Energ_Kcal = d.Sum_Energ_Kcal
WHERE d.id1 = a.fsdsnum
AND a.mfdfsds = aallinnot2.NDB_No
AND c.NDB_No IN (
SELECT DISTINCT `fsdsnum`
FROM `aaingred`
WHERE `usernum` LIKE '42'
);
I'm not sure about mysql, but with SQL Server the statement would be something like this:
UPDATE aallinnot2
SET Energ_Kcal = (
SELECT SUM( c.Energ_Kcal)
FROM aaingred a
LEFT JOIN aaweight b ON a.unit = b.uni
LEFT JOIN aallinnot2 c ON a.mfdfsds = c.NDB_No
LEFT JOIN aalinfsds d ON a.fsdsnum = d.id1
WHERE d.own_id =42)
WHERE c.NDB_No
IN ( SELECT DISTINCT `fsdsnum`
FROM `aaingred`
WHERE `usernum` LIKE '42')
You can't alias the table to be updated in the UPDATE clause, but you can in the FROM clause.

How to update fields that is the aggregate result of another table in MySQL?

UPDATE a JOIN b ON a.app_id=b.app_id GROUP BY a.app_id SET
remark_avg=AVG(b.score),remark_count=COUNT(b.id);
The above is basically what I want to do,but it's not a valid MySQL statement,how to write it correctly?
UPDATE a
INNER JOIN (SELECT AVG(b.score) avg_score,
COUNT(b.id) cnt_id,
b.app_id
FROM b
GROUP BY b.app_id) x ON x.app_id = a.app_id
SET remark_avg = x.avg_score,
remark_count = x.cnt_id;

Is there a way to optimize this update query?

I have a master table called "parent" and a related table called "childs"
Now I run a query against the master table to update some values with the sum from the child table like this.
UPDATE master m SET
quantity1 = (SELECT SUM(quantity1) FROM childs c WHERE c.master_id = m.id),
quantity2 = (SELECT SUM(quantity2) FROM childs c WHERE c.master_id = m.id),
count = (SELECT COUNT(*) FROM childs c WHERE c.master_id = m.id)
WHERE master_id = 666;
Which works as expected but is not a good style because I basically make multiple SELECT querys on the same result. Is there a way to optimize that? (Making a query first and storing the values is not an option.
I tried this:
UPDATE master m SET (quantity1, quantity2, count) = (
SELECT SUM(quantity1), SUM(quantity2), COUNT(*)
FROM childs c WHERE c.master_id = m.id
) WHERE master_id = 666;
but that doesn't work.
Update: Here is the solution, thanks to everbody:
You can do something like this:
UPDATE master m
INNER JOIN childs c ON m.master_id = c.master_id
SET master.quantity1 = c.quantity1,
master.count = 1
If you have only one child record at a time. However if you want to use a group function like SUM() in the joined table that doesn't work. Either you get a "Invalid use of group function" if you leave the "group by" part or a "You have an error in your sql syntax if you use "GROUP BY c.master_id"
-- This doesnt work :(
UPDATE master m
INNER JOIN childs c ON m.master_id = c.master_id
SET master.quantity1 = SUM(c.quantity1),
master.count = COUNT(c.*)
GROUP by c.master_id
The solution is to use JOIN with a subquery:
UPDATE master m
INNER JOIN
(
SELECT master_id,
SUM(quantity1) as quantity1,
COUNT(*) as count
FROM childs c
GROUP BY master_id
) c
ON c.master_id = m.master_id
SET m.quantity1 = c.quantity1,
m.count = c.count
WHERE m.master_id = 666;
But since this pulls every row from the childtable the overhead would likely be bigger than using more subqueries like in the original sql. So you should add a WHERE clause to the joined table to get only the rows you need.
Another interesting approach is this syntax, which does the same as the JOIN with the WHERE clause but you should only use if if you want to update all rows with the same values and your subquery only returns one row, since the result from the subquery gets appended to the result and can be used like any column.
UPDATE master m,
(
SELECT SUM(c.quantity1) as sum_of_quantity,
COUNT(*) as rowcount FROM child c WHERE c.master_id = 666
) as c
SET m.quantity1 = c.sum_of_quantity,
m.count = c.rowcount
WHERE m.master_id = 666;
Rewriting Lieven's solution to MySQL:
UPDATE master m
JOIN (
SELECT master_id
, SUM(quantity1) as quantity1
, SUM(quantity2) as quantity2
, COUNT(*) as count
FROM childs c
GROUP BY
master_id
) c
ON c.master_id = m.master_id
SET
m.quantity1 = c.quantity1
,m.quantity2 = c.quantity2
,m.count = c.count
WHERE m.master_id = 666;
I don't know if it is allowed in MySQL, but SQL Server allows you to use the result of a select in an update.
UPDATE master m SET
quantity1 = c.quantity1
, quantity2 = c.quantity2
, count = c.count
FROM master m
INNER JOIN (
SELECT master_id
, quantity1 = SUM(quantity1)
, quantity2 = SUM(quantity2)
, count = COUNT(*)
FROM childs c
WHERE master_id = 666
GROUP BY
master_id
) c ON c.master_id = m.master_id
You could select your data into a temporary table, and then update using that data.
If you also want to insert "new" data in the same roundtrip, look into INSERT INTO ... SELECT FROM ... ON DUPLICATE KEY UPDATE ...
If you already are doing inserts if row doesn't exist, then that would be redundant with this example.
example:
INSERT INTO master m (id, quantity1, quantity2, count)
SELECT master_id, SUM(quantity1) q1, SUM(quantity2) q1, COUNT(*) c
FROM childs
GROUP BY master_id
ON DUPLICATE KEY UPDATE
m.quantity1 = q1,
m.quantity2 = q2,
m.count = c
NOTE! This is untested code, but I think it should be possible to backreference the select result in the UPDATE.
Syntax reference: http://dev.mysql.com/doc/refman/5.0/en/insert.html