I have a mysql query where I need to calculate values like ROUND(SUM(temp.total_pq),2) multiple times, so I defined variables to avoid repeating them.
But the line 5 in the query returns wrong value in the results. The value for #diff_client_partner_qtty := ROUND((#partner_qtty_all_runs - #client_qtty_all_runs), 2) AS diff_client_partner_qtty is always NULL the first time I run and thereafter always 84.
I asked the in-house DBA and he says I should not use variables in my query like this because the order in which mysql will set values for the variable is not predictable and hence I may get NULL value.
But why? Also can someone please propose then another way whereby I can avoid rewriting ROUND(SUM(temp.total_pq),2) multiple times other than a subquery. I would prefer to avoid a subquery because I think even in its current form query is not that readable.
SELECT temp.dtaccounted AS accounting_period,
#partner_qtty_all_runs := ROUND(SUM(temp.total_pq),2) AS partner_qtty_all_runs,
ROUND(temp.mmq,2) AS mopay_qtty,
#client_qtty_all_runs := ROUND(SUM(temp.total_cq),2) AS client_qtty_all_runs,
#diff_client_partner_qtty := ROUND((#partner_qtty_all_runs - #client_qtty_all_runs), 2) AS diff_client_partner_qtty,
#partner_gtv := ROUND(temp.total_pq_gtv, 2) AS partner_gtv,
#client_gtv := ROUND(temp.total_cq_gtv,2) AS client_gtv,
#diff_client_partner_gtv := ROUND((#partner_gtv - #client_gtv), 2) AS diff_client_partner_gtv,
temp.stariffcurrency AS tariffcurrency,
ROUND(#diff_client_partner_gtv * ffactor, 2) AS diff_client_partner_gtv_eur,
temp.scountry AS country,
temp.spartnererpid AS partner_erp_id,
c.name AS partner_name,
temp.nproducttype AS product,
temp.capping
FROM
(SELECT SUM(npartnerquantity) AS total_pq,
SUM(nmindmaticsquantity) AS mmq,
SUM(nclientquantity) AS total_cq,
SUM(dgrosstariff * npartnerquantity) AS total_pq_gtv,
SUM(dgrosstariff * nclientquantity) AS total_cq_gtv,
nrun,
vb.scountry,
vb.spartnererpid,
dtaccounted,
stariffcurrency,
vb.nproducttype,
cq.bisenabled AS capping
FROM report_table vb,
client_table cq
WHERE vb.accperiod > '2013-12-01'
AND vb.partnerid = cq.partnerid
AND vb.scountry = cq.scountry
AND vb.nproducttype = cq.nproducttype
AND (cq.dtvalidto IS NULL
OR cq.dtvalidto > vb.accperiod)
GROUP BY scountry,
nproducttype,
partnerid,
nrun,
accperiod
) temp,
customer c,
currency_conversion cc
WHERE temp.partnerid = c.erp_id
AND temp.total_pq <> temp.total_cq
AND cc.scurrencyfrom = temp.stariffcurrency
AND cc.scurrencyto = 'EUR'
AND cc.dtrefdate = temp.accperiod
GROUP BY temp.scountry,
temp.partnerid,
c.name,
temp.nproducttype,
temp.accperiod
ORDER BY temp.accperiod,
temp.scountry,
temp.partnerid,
temp.nproducttype,
temp.capping \G;
Related
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
I have been trying to make this work for hours but I can't really find a way to do it. I have a MySQL script that I need to migrate to MS SQL 2014, however, I can't seem to make it work. As far as I have understood, the big issue is that MySQL allows this kind of instructions:
SELECT #row_number = #row_number + 1, hora_int FROM table1;
where you assign a value at the same time you retrieve data, but MS SQL does not.
I have a relatively big script which has that issue:
SELECT GLOBAL.year, GLOBAL.month, '1111111' as metric_id, GLOBAL.margin as metric_value FROM (SELECT A.year,
A.month,
CASE
WHEN A.month = 1 THEN (#csum_fdo := A.imp)
ELSE (#csum_fdo := #csum_fdo + A.imp) END as margin
FROM (SELECT Act.year, Act.month, Act.imp - Pas.imp as imp
FROM (SELECT year(tie.date) as year, month(tie.date) as month, sum(importe) as imp
FROM accounting con,
dim_time tie,
dim_account cta
WHERE con.account_date = tie.date
AND con.account = cta.nivel_10
AND cta.level_id = '2'
AND con.subtype_id <> 'O'
GROUP BY year(tie.date),
month(tie.date)) Act,
(SELECT year(tie.date) as year, month(tie.date) as month, sum(importe) * -1 as imp
FROM accounting con,
dim_time tie,
dim_account cta
WHERE con.account_date = tie.date
AND con.account = cta.nivel_10
AND cta.level_id = '3'
AND con.subtype_id <> 'O'
GROUP BY year(tie.date),
month(tie.date)) Pas
WHERE Act.year = Pas.year
AND Act.month = Pas.month) A,
(SELECT #csum_fdo := 0) E) GLOBAL
Can anybody point me in the direction of what I have to do to recreate the code in MS SQL? Thank you all in advance
In SQL Server and (MyQL 8+), you use window functions. The equivalent of:
SELECT #row_number = #row_number + 1, hora_int
FROM table1
ORDER BY col;
is:
SELECT ROW_NUMBER() OVER (ORDER BY col), hora_int
FROM table1;
If you provide sample data and desired results, it is much easier to figure out what functions you really need.
My big problem lied in this line:
CASE
WHEN A.month = 1 THEN (#csum_fdo := A.imp)
ELSE (#csum_fdo := #csum_fdo + A.imp) END as margin
but as Gordon Linoff pointed me. this problem could be solved with window functions, the right translation od that function is:
SUM(A.imp) OVER(PARTITION BY A.Year ORDER BY A.month) as margin
it ended up being easier than I thought
Thanks a lot and I hope it can help others as well
I"m trying to add a new col that shows the rank (or sequence) of row results by date.
I've written:
SELECT
#row_number:=(CASE
WHEN #member_id = lh.member_id and lc.ladder_advocacy is not null
THEN #row_number + 1
when #member_id = lh.member_id and lc.ladder_advocacy is null then "null"
ELSE 1 /* there is an error here - i need it to return a 1 if not null, then 2 for the 2nd instance, etc */
END) AS rank_advocacy,
#member_id:=lh.member_id AS member_id,
lh.ladder_change,
lc.name,
lc.ladder_advocacy,
lc.ladder_elected,
lc.ladder_policy,
lc.ladder_engagement,
lc.ladder_newventure,
lc.ladder_collective,
lc.is_trigger
FROM
leenk_ladder_history AS lh
LEFT JOIN
leeds_so.leenk_ladder_config AS lc ON lh.ladder_config_id = lc.id
WHERE
ladder_change = 1 AND trigger_active = 1
ORDER BY member_id, trigger_event_date DESC;
There is an error at row 4, and I'm not sure how to fix it. For the first result, I want to return 1. for the second results, I want to return #row_number + 1. Third result, #row_number+2 (etc).
How do I achieve this?
I don't understand how the condition lc.ladder_advocacy is not null is being used. However, the basic structure is:
SELECT (#row_number = IF(#member_id = lh.member_id, #row_number + 1
IF(#member_id := lh.member_id, 1, 1)
)
) as rank_advocacy,
lh.ladder_change,
. . .
Some really important points:
You need to assign #member_id and #row_number in the same expression. MySQL (as with all other databases) does not guarantee the order of evaluation of expressions.
In more recent versions of MySQL, I think the ORDER BY needs to go in a subquery, with the variable expressions in the outer query.
I am stuck in a query I want to store sum result in a variable where status = 3, what happening right now is it store the value of last row and show it with all rows
Here is the query
SELECT
request_made_on,driver_id,
#sum_result = SUM(status = 3) AS complete_count,#sum_result,
SUM(status = 6) AS missed_count,
(status = 4) AS canceled_count,
sum(actual_fare),sum(discount)
from tb_engagements
group by date(request_made_on),driver_id;
and here is the screenshot,
second screenshot
I'm guessing that you want the sum of all the values:
select request_made_on, driver_id,
(#sum_result := #sum_result + SUM(status = 3)) AS complete_count,
sum(status = 6) AS missed_count,
sum(status = 4) AS canceled_count,
sum(actual_fare),
sum(discount)
from tb_engagements c cross join
(select #sum_result := 0) params
group by date(accept_time), driver_id;
Notes:
You don't need to return the value of the variable as well as the expression. The expression adds a column to the result set with the value.
You don't need if() to count values. MySQL has a nice short-hand, treating boolean expressions as integers in a numeric context.
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.