Shorten the mysql case query - mysql

I have written this query but it seems a very bad query,
select * from games_applied where
games_post_id='1126' and status != '4' and
(status != '5' and rejected_status = '0' or status = '5' and rejected_status = '1');
How to make use of this case in a better way.
(status != '5' and rejected_status = '0' or status = '5' and rejected_status = '1')
should only display the rows which has rejected_status = 1 and status = 5
and should not display the rows which has rejected_Status = 0 and status = 5

This is not a major simplification, but it does remove the comparison to 4. However, this is how I would write the query:
select ga.*
from games_applied ga
where ga.games_post_id = 1126 and
( (ga.status not in (4, 5) and ga.rejected_status = 0) or
(ga.status = 5 and ga.rejected_status = 1)
);
Notes:
The table has a meaningful table alias.
All the column names are qualified.
I assume that the numbers are really comparisons for numeric columns, so I removed the single quotes.
I removed the comparison to "4".

The only improvements that your query needs, is to encapsulate the two clauses on either side of your or statement. In other words, put your status and rejected_status check inside parentheses.
select
*
from
games_applied
where
games_post_id='1126'
and status != '4'
and
(
(status != '5' and rejected_status = '0')
or (status = '5' and rejected_status = '1')
);

Here is the query hopefully it works as required :
select * from games_applied where
games_post_id='1126' and status != '4' and case when status='5' then
rejected_status='1' else rejected_status='0' end;

Related

Turning a column in to a string

I want to make 1 query but it is hit by performance issues due to this warning:
Warning: #1292 Truncated incorrect DOUBLE value: ''
See I have this query:
SELECT b.ID,
(SELECT SUM(case when ABBO != '0' then 1 else 0 end)
FROM OCCASIONS where HBODBED = b.ID) as BEOORDELINGEN,
(SELECT SUM(case when ABBO != '0' then ABBO else 0 end)
FROM OCCASIONS where HBODBED = b.ID) as TOTAAL
FROM BEDRIJVEN b WHERE ACTIVE = '1' AND GROEP = '0'
ORDER BY APERC DESC LIMIT 0, 50;
But HBODBED is a varchar(30) and b.ID is a bigint(20)
so lets run a single query:
SELECT SUM(case when ABBO != '0' then ABBO else 0 end) as total,
SUM(case when ABBO != '0' then 1 else 0 end) AS BEOORDELINGEN
FROM OCCASIONS where HBODBED = 59;
still gets warnings and execution time is 0.6498 seconds not bad but if you run 2 of those 50 times it adds up
But if I add string markers to 59 like this: '59' it removes the warnings and the execution time is reduced to 0.0078 seconds so my question is:
How can I add those string markers to b.ID in the top query?
You have this join condition:
WHERE HBODBED = b.ID
where you are comparing varchar(30) with a bigint. MySQL will convert both operands to floating-point numbers and compare them. Besides conversion, the comparison of floating point numbers itself is an expensive operation.
The correct solution is to convert the datatype of columns so that they match. If that is not an option, you can try converting one of the operands:
WHERE HBODBED = CAST(b.ID AS char)
WHERE CAST(HBODBED AS signed) = b.ID
Now only one of the operands is converted. When converting to bigint you will still get "truncated incorrect INTEGER value" warning for values that did not convert to float earlier.

Find duplicates in mySQL but with a specific status

I have an orders table and I need to find the duplicates - orders which have the same dd_number and dd_code, BUT one of the orders must have the status of "checkout_completed".
The following is my current SQL which correctly finds duplicate orders which have the same dd_number and dd_code, however I cant work out how to check for the status:
SELECT
tbOrders.id, tbOrders.dd_number, tbOrders.dd_code, tbOrders.status, COUNT(*) AS totalDupes
FROM
tbOrders
WHERE
dd_number IS NOT NULL
AND
dd_number != ''
AND
dd_number != '000000'
AND
dd_number != '00000000'
GROUP BY
dd_number, dd_code
HAVING totalDupes > 1
Adding a WHERE clause of status = 'checkout_complete' does not work as it requires both orders to have the same status. Any help would be greatly appreciated!
SELECT
tbOrders.id, tbOrders.dd_number, tbOrders.dd_code, tbOrders.status, COUNT(*) AS totalDupes,
SUM(CASE WHEN status='checkout_complete' THEN 1 ELSE 0 END) as status_count
FROM
tbOrders
WHERE
dd_number IS NOT NULL
AND
dd_number != ''
AND
dd_number != '000000'
AND
dd_number != '00000000'
GROUP BY
dd_number, dd_code
HAVING totalDupes > 1 and status_count=1
You can introduce one more aggregate field counting records with the status
Mmm, multiple way of doing it. I'd suggest using the HAVING clause with conditional aggregation :
HAVING totalDupes > 1
AND MAX(CASE WHEN status = 'checkout_complete' THEN 1 ELSE 0 END) = 1
Though your query seems wrong. If ID is unique, then a random ID will be choosen , same goes for STATUS . All the columns should either be in the GROUP BY or wrapped with an aggregation function. Note that only MySQL older versions accept your syntax. In any other RDBMS this will throw an error.

Update two tables at once, using values from first table

So I need to Update table scores and use the updated value of column won to update the second table tbl_users. So far the code updates scores, but uses the old value of won for the second table update:
UPDATE scores a
left join tbl_users b on
a.uid = b.userID
SET a.won = CASE
WHEN a.nright = '0' THEN '0'
WHEN a.nright = '1' THEN '25'
WHEN a.nright = '2' THEN '50'
WHEN a.nright = '3' THEN '100'
WHEN a.nright = '4' THEN '200'
WHEN a.nright = '5' THEN '400'
WHEN a.nright = '6' THEN '700'
WHEN a.nright = '7' THEN '1000'
END,
b.pts=b.pts+a.won,
b.pts_total=b.pts_total+a.won
WHERE a.uid=$user AND b.userID=$user
What you want to do is explicitly documented as correct:
The second assignment in the following statement sets col2 to the
current (updated) col1 value, not the original col1 value. The result
is that col1 and col2 have the same value. This behavior differs from
standard SQL.
UPDATE t1 SET col1 = col1 + 1, col2 = col1;
I assume that the issue is the multi-table update, where the set pulls the value from the earlier table.
You may be able to fix this using variables. I am not 100% sure, but the following is worth a try:
UPDATE scores s JOIN
tbl_users u
ON s.uid = .uuserID
SET s.won = (#w := (CASE WHEN s.nright = '0' THEN '0'
WHEN s.nright = '1' THEN '25'
WHEN s.nright = '2' THEN '50'
WHEN s.nright = '3' THEN '100'
WHEN s.nright = '4' THEN '200'
WHEN s.nright = '5' THEN '400'
WHEN s.nright = '6' THEN '700'
WHEN s.nright = '7' THEN '1000'
END)
),
u.pts = u.pts + #w,
u.pts_total = u.pts_total + #w
WHERE s.uid = $user ;
The documentation strongly suggests that the set clauses are processed in order for a single table. Alas, it is not clear whether this is always true for multiple tables.
If not, you can use two updates.

not retrieving exact result from case statement

I am using below query but Y column not retrieving exact result. Could you guys please help me out
SELECT FAPI.*,
CASE WHEN (SELECT DISTINCT 'Y'
FROM FLOOR_PI FAPI,
NUATON NUMF
WHERE FAPI.BRCH = NUMF.BRCH
AND FAPI.BASE = NUMF.BASE
AND FAPI.NUM = 0
AND NVL(FAPI.RATION, 'X') <> 'D'
AND FAPI.CODE = 'A'
AND NUMF.R_DATE
BETWEEN FAPI.EFF_DATE
AND FAPI.EXP_DATE ) = 'Y'
THEN 'Y'
ELSE 'N' END NEW
FROM FLOOR_PI FAPI
Thank you,
Rave
Based on #SlimsGohst comment:
You should replace FAPIx with FAPI1 or FAPI2 whichever is applicable
SELECT FAPI1.*,
CASE WHEN (SELECT DISTINCT 'Y'
FROM FLOOR_PI FAPI2,
NUATON NUMF
WHERE FAPIx.BRCH = NUMF.BRCH
AND FAPIx.BASE = NUMF.BASE
AND FAPIx.NUM = 0
AND NVL(FAPIx.RATION, 'X') <> 'D'
AND FAPIx.CODE = 'A'
AND NUMF.R_DATE
BETWEEN FAPIx.EFF_DATE
AND FAPIx.EXP_DATE ) = 'Y'
THEN 'Y'
ELSE 'N' END NEW
FROM FLOOR_PI FAPI1

SQL ORDER BY query

I want to have my table,rcarddet, ordered by "SDNO" (not primary key) in ascending order with the exception of "0". So it should turn out to be like:
1
1
2
.
.
10
0
0
My query now is:
SELECT *
FROM `rcarddet`
WHERE `RDATE` = '2011-05-25'
AND `RCNO` = '1'
AND `PLACE` = 'H'
AND `SDNO` != 0
ORDER BY `rcarddet`.`SDNO` ASC;
The easiest way
SELECT * FROM rcarddet
WHERE RDATE = '2011-05-25' and RCNO = '1'and PLACE = 'H'
ORDER BY CASE
WHEN rcarddet.SDNO = 0 THEN [max_number_for_the_type_of_SDNO]
ELSE rcarddet.SDNO
END ASC
SELECT *
FROM `rcarddet`
WHERE `RDATE` = '2011-05-25'
AND `RCNO` = '1'
AND `PLACE` = 'H'
ORDER BY
`SDNO` = 0,
`SDNO`;