UPDATE from SELECT but still return selected data in MySQL - mysql

I have read a bunch of ways that has gotten me this far. But I can't get to the finish line.
I have a table of coupon codes. I want to use one transaction to select the next available code, mark it as used and input the order number. I can get the update and nested select to work, but I cannot figure out how to actually return the coupon code from the select. It just returns 1 row updated.
Here's what I've got:
UPDATE `prcoupon` pr
SET
`pr`.`status` = '1',
`pr`.`invoicenumber` = '09990002'
WHERE
`pr`.`couponCode` = (SELECT
`prcoupon`.`couponcode`
FROM
`prcoupon`
WHERE
`status` = 0
LIMIT 1)
Sample data
What I need returned is: couponCode: SL2T-03A0-JVCY-W2XMXG

If I understand correctly, you can try to use UPDATE ... JOIN with ROW_Nunber windwon function.
UPDATE prcoupon pr
JOIN (
SELECT *,ROW_NUMBER() OVER(ORDER BY couponCode) rn
FROM prcoupon
WHERE status = 0
) t2 ON pr.couponcode = t2.couponcode
SET pr.status = 1,
pr.invoicenumber = '09990002'
WHERE rn = 1
sqlfiddle

Related

mysql update with if and max

I have lost hours on this and nothing works for me.
I have filed strp_aa that is default NULL. The filed strp_aa should update only if its null with MAX strp_aa + 1, and if its not null if it already has a number it should stay the same.
short version of code is
UPDATE STRANKEP
SET strp_aa = IF(strp_aa=null, strp_aa+1, strp_aa)
WHERE strp_ID=36;
Also tired
UPDATE STRANKEP
SET strp_aa = IF(strp_aa=null, (SELECT MAX(strp_aa)) +1, (SELECT (strp_aa) WHERE strp_ID=36)
WHERE strp_ID=36;
I tried multiple things like this one mentioned here Update MySQL with if condition:
UPDATE STRANKEP
SET strp_aa = CASE WHEN strp_aa = NULL THEN MAX(strp_aa) + 1 ELSE strp_aa END
WHERE strp_ID = 36;
I have also found this mysql query to update field to max(field) + 1 and tried all sorts of combinations with supplied answer and it wont work for me. One of the version is:
UPDATE STRANKEP
SET strp_aa = IF((SELECT strp_aa )!=null,((SELECT selected_value2 FROM (SELECT (strp_aa) AS selected_value2 FROM STRANKEP WHERE strp_ID=36) AS sub_selected_value2)), ((SELECT selected_value FROM (SELECT MAX(strp_aa) AS selected_value FROM STRANKEP) AS sub_selected_value) + 1) )
WHERE strp_ID=36;
This just keep adding one even if there is a number set on strp_aa...
I don't know what else to try.
EDIT:
Had s little problem with #GMB answer because all fields are starting with NULL, so max(strp_aa) gives 0 results in case none of the fields had a number in it.
I solved that with COALESCE statement and posting it here if someone has similar problem.
UPDATE STRANKEP t
CROSS JOIN (select COALESCE(MAX(strp_aa),0) max_strp_aa from STRANKEP) m
set t.strp_aa = m.max_strp_aa + 1
where t.strp_ID = 36 and t.strp_aa is null
You can use the update ... join syntax for this:
update strankep s
cross join (select max(strp_aa) max_strp_aa from strankep) m
set s.strp_aa = m.max_strp_aa + 1
where s.strp_id = 36 and s.strp_aa is null
The cross join brings the max value of strp_aa over the whole table. The where clause eliminate row(s) where strp_aa is not null.

Subquery returned more than 1 value.4...Different query

Hello I have this query that i am trying to execute and i keep getting this error "Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.", Kindly help please.
DECLARE #NUMCOUNT BIT
Select #NUMCOUNT = (SELECT
CASE WHEN
(SELECT COUNT(R5REQUISLINES.RQL_REQ)
WHERE R5REQUISLINES.RQL_STATUS IN ('A')
) IN
(SELECT COUNT(R5REQUISLINES.RQL_REQ)
WHERE R5REQUISLINES.RQL_STATUS IN ( 'A','C') ) THEN 1 else 0 END AS NUMCOUNT1
FROM R5REQUISLINES JOIN
R5REQUISITIONS ON R5REQUISLINES.RQL_REQ = R5REQUISITIONS.REQ_CODE
GROUP BY R5REQUISLINES.RQL_REQ, R5REQUISITIONS.REQ_CODE,R5REQUISLINES.RQL_STATUS
)
IF #NUMCOUNT = '1'
begin
UPDATE R5REQUISITIONS
SET R5REQUISITIONS.REQ_STATUS = 'CP'
end
Ok, it sounds like what you actually want to do is update R5REQUISITIONS when there is no RQL_STATUS = 'C' in R5REQUISLINES, since you said you want to count the records where the RQL_STATUS is A and where it's A or C, and then do the update if the counts are the same.. You can greatly simplify this task with the following query:
UPDATE r5
SET r5.REQ_STATUS = 'CP'
FROM R5REQUISITIONS r5
WHERE NOT EXISTS (SELECT 1 FROM R5REQUISLINES r5q WHERE r5q.RQL_REQ = r5.REQ_CODE AND r5q.RQL_STATUS = 'C')
Your 'SELECT CASE' is returning more than 1 record, so it can't be assigned to #NUMBER. Either fix the sub-query to only return the record your looking for or hack it to return only 1 with a 'LIMIT 1' qualification.
I don't know what your data looks like so I can't tell you why your case subquery returns more records than you think it should.
Try running this and see what it returns, that will probably tell you wall you need to know:
SELECT
CASE WHEN
(SELECT COUNT(R5REQUISLINES.RQL_REQ)
WHERE R5REQUISLINES.RQL_STATUS IN ('A')
) IN
(SELECT COUNT(R5REQUISLINES.RQL_REQ)
WHERE R5REQUISLINES.RQL_STATUS IN ( 'A','C')
)
THEN 1
ELSE 0
END AS NUMCOUNT1
FROM R5REQUISLINES JOIN
R5REQUISITIONS ON R5REQUISLINES.RQL_REQ = R5REQUISITIONS.REQ_CODE
GROUP BY R5REQUISLINES.RQL_REQ, R5REQUISITIONS.REQ_CODE,R5REQUISLINES.RQL_STATUS
If there is more than 1 row returned, that's where your problem is.

Slow mySql update containing Join

I have a system that collects data from production reports (CSV files) and puts them into a mySql DB.
I have an header table, that contain the production data of sequential report with same setting, and a table with the single reports, connected to the first one (trfCamRep.hdrId -> trfCamHdr.id).
I have a query to calculate the total report, the dubt and the faulty, and the maxTs. These datas are used in the visualizator.
The query is too slow, it requires 9sec.
Can you help me to speed up it?
SET #maxId:=(SELECT MAX(id) FROM trfCamHdr WHERE srcCod='7');
UPDATE trfCamHdr AS hdr
LEFT JOIN (SELECT hdrF.id,COUNT(*) AS nTot,
SUM(IF(res=1,1,0)) AS nWrn,SUM(IF(res=2,1,0)) AS nKO,
MAX(ts) AS maxTS
FROM trfCamHdr AS hdrF
JOIN trfCamRep AS repF ON repF.hdrId=hdrF.id
WHERE clcEnd=0 AND srcCod='7'
GROUP BY hdrF.id) AS valT ON valT.id=hdr.id
SET hdr.clcEnd=IF(hdr.id<#maxId,1,0),
hdr.nTot=valT.nTot,
hdr.nWrn=valT.nWrn,
hdr.nKO=valT.nKO,
hdr.maxTS=valT.maxTS
WHERE hdr.id>=0 AND hdr.clcEnd=0 AND hdr.srcCod='7';
Note trfCamHdr has these columns:
id (primary key)
clcEnd : flag of end calculation (the last remain to 0 because in progress)
nTot : elements with this header
nWrn : elements with res = 1
nKO : elements with res = 2
maxTs : TS of the last element
trfCamRep has these columns:
hdrId (refer to id of trfCamHdr)
res : 0 good, 1 dubt, 2 fault
ts : report timestamp
I'd take this out:
SET #maxId:=(SELECT MAX(id) FROM trfCamHdr WHERE srcCod='7');
And any allusions to the MaxId variable, I believe it to be redundant.
Everything you do will be lower than the max id, and it will take time to calculate if its a big table. You are already checking for srcCod = 7, so it isn't necessary.
In fact, it would miss the update on the one with the actual max id, which is not what I believe you want.
Your left join will also update all other rows in the table with NULL, is that what you want? You could switch that to an inner join, and if your rows are already null, they will just get left alone, rather than getting updated with NULL again.
Then you could just switch out this:
SET
hdr.clcEnd = IF(hdr.id < #maxId, 1, 0),
To
SET
hdr.clcEnd = 1,
Here is the rewritten thing, as always, back your data up before trying:
UPDATE trfCamHdr AS hdr
INNER JOIN
(SELECT
hdrF.id,
COUNT(*) AS nTot,
SUM(IF(res = 1, 1, 0)) AS nWrn,
SUM(IF(res = 2, 1, 0)) AS nKO,
MAX(ts) AS maxTS
FROM
trfCamHdr AS hdrF
JOIN trfCamRep AS repF ON repF.hdrId = hdrF.id
WHERE
clcEnd = 0 AND srcCod = '7'
GROUP BY hdrF.id) AS valT ON valT.id = hdr.id
SET
hdr.clcEnd = 1,
hdr.nTot = valT.nTot,
hdr.nWrn = valT.nWrn,
hdr.nKO = valT.nKO,
hdr.maxTS = valT.maxTS
WHERE
hdr.id >= 0 AND hdr.clcEnd = 0
AND hdr.srcCod = '7';
I found the solution: I created a KEY on hdrId column and now the query requires 0.062s.

Update SQL records with values from another record

I'm spinning in circles trying to figure out what is likely a very simple SQL structure. My task seems simple - within the same table I need to update 3 related records with data from one master record. The master coordinates are in the record with a class of 'T', and I want to insert that record's coordinates into the rx_latitude/longitude columns of the related records with class code 'R'
The table structure is: callsign, class, tx_latitude, tx_longitude, rx_latitude, rx_longitude. Sample data looks like this:
J877, T, 40.01, -75.01, 0, 0
J877, R, 39.51, -75.21, 0, 0
J877, R, 40.25, -75.41, 0, 0
J877, R, 39.77, -75.61, 0, 0
Within that same table, I want to populate all of the rx_latitude and rx_longitude fields where the class is 'R' with the tx_latitude and tx_longitude coordinates where the class is 'T' and the callsign matches.
I've tried several insert and update statements, but I can only seem to operate on the master record, not the related records. I would appreciate any guidance that you might offer.
You can use UPDATE...FROM statement:
UPDATE theTable
SET
tx_latitude = masterRecord.tx_latitude,
tx_longitude = masterRecord.tx_longitude
FROM
(SELECT tx_latitude,tx_longitude,callsign FROM theTable WHERE class='T') masterRecord
WHERE
class='R' AND callsign = masterRecord.callsign
Updated
Try :
update yourTable t1, yourTable t2 set
t1.tx_latitude = t2.tx_latitude,
t1.tx_longitude = t2.tx_longitude
where t1.class = 'R' and t2.class = 'T' and t1.callsign = t2.callsign
Example
You can use MySQL's update ... join syntax.
It would go something like this:
update yourtable toUpdate
left join yourtable masterRecordTable
on toUpdate.callsign = masterRecordTable.callsign and masterRecordTable.class = 'T'
set toUpdate.rx_latitude = masterRecordTable.tx_latitude,
toUpdate.rx_longitude = masterRecordTable.tx_longitude
where toUpdate.callsign = 'J877' and toUpdate.class = 'R'
See this fiddle for a working example

Trying to merge multiple UPDATE statements into one within SQL stored procedure

I have multiple update statements in a stored procedure (as shown below).
Question is I am trying to combine them into one UPDATE statement as there is a performance issue (takes longer to execute stored procedure). I tried putting columns (such as PONUMBER, VENDORID etc) in a single update statement but it is throwing errors.
Please suggest.
UPDATE rptMaster SET PONUMBER = (select top 1 poMaster.PONUMBER from poMaster where poMaster.ITEMNMBR =rptMaster.ITEMNMBR and
poMaster.UnCommited > 0)
UPDATE rptMaster SET VENDORID = (select top 1 poMaster.VENDORID from poMaster where poMaster.ITEMNMBR =rptMaster.ITEMNMBR and
poMaster.UnCommited > 0)
UPDATE rptMaster SET DUEDATE = (select top 1 poMaster.REQDATE from poMaster where poMaster.ITEMNMBR =rptMaster.ITEMNMBR and
poMaster.UnCommited > 0)
UPDATE rptMaster SET POQTYORDER = (select top 1 (poMaster.QTYORDER / rptMaster.UOMQTY) from poMaster where poMaster.ITEMNMBR =rptMaster.ITEMNMBR and
poMaster.UnCommited > 0)
Mine is similar to polkduran's:
WITH PO AS (
SELECT PONUMBER
, VENDORID
, REQDATE
, QTYORDER
, ITEMNMBR
, ROW_NUMBER() OVER (PARTITION BY ITEMNMBR ORDER BY ??) as RN
FROM poMaster
WHERE UnCommited > 0
)
UPDATE rptMaster
SET PONUMBER = po.PONUMBER
, VENDORID = po.VENDORID
, DUEDATE = po.REQDATE
, POQTYORDER = po.QTYORDER / rptMaster.UOMQTY
FROM rptMaster
JOIN PO
ON PO.ITEMNMBR = rptMaster.ITEMNMBR
and PO.RN = 1
I'm using a Common Table Expression (CTE) to assign a row number to each poMaster record, with the records for each value of ITEMNMBR numbered separately. This allows us to pick to the first record for each ITEMNBR in our JOIN, later, similar to the way you were using Top 1 in your subqueries.
Please note, though: because you didn't indicate how you wanted to select the Top 1 record in your query, I had to leave the ORDER BY clause in the CTE unspecified. (I put ?? in as a placeholder.) You need to specify one or more sort fields in place of the ?? so it knows how to sort and number the records.
You can make an update using a join clause:
update rpt
set
PONUMBER = po.PONUMBER,
VENDORID = po.VENDORID,
DUEDATE = po.REQDATE,
POQTYORDER = (po.QTYORDER / rpt.UOMQTY)
from rptMaster rpt
inner join poMaster po
on po.ITEMNMBR = rpt.ITEMNMBR
where po.UnCommited > 0
I don't have a way to test it right now but that might work.