Turning a column in to a string - mysql

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.

Related

Diffrence between sum of two products > 0

I want to select the sum of T_No where Transactions are equal to R and subtract it by T_No where Transactions are equal to D and the answer of this should greater than zero for a CustomerID which would be a input (an int input declared in a stored procedure)
((Sum(T_No) where Transactions = R - Sum(T_No) where Transactions = D ) > 0) where CoustomerID = #input
Example : for ID = 1 it would be ((20+15) - 10) > 0
I Have tried so many things but either syntax is wrong, wrong value or it does not accept, and I am literally Stuck, this was my final attempt
SELECT
(select ( select Sum(T_No) where Transactions = R) - (select Sum(T_No) where Transactions = D) as C_T )
FROM CustomerTrans WHERE C_T > 0 ;
Conditional aggregation should help:
SELECT
SUM(CASE WHEN Transaction = 'R' THEN t_no ELSE 0 END) - SUM(CASE WHEN Transaction = 'D' THEN t_no ELSE 0 END)
FROM CustomerTrans
WHERE CoustomerID = #yourCustomerIdVariable
As you're writing a sproc you can assign the result of this to a variable and then decide what to do if the result is negative. (I would personally log an error for example, rather than just hide those results). If the result is null, then there were no transactions for that customer
ps; I used Transaction because that's what your screenshot showed, and I figured a screenshot is less likely to contain a typo than code with syntax errors. Adjust if required
you where kinda close, I would sum like you, only the syntax is a bit off, you can't have aggregate fields in Where, thats why you should use having, also case when syntax is not correct.
Select
CoustomerID,
Sum(case when Transactions = 'R' then T_No else 0 end) -
Sum(case when Transactions = 'D' then T_No else 0 end) as C_T
FROM CustomerTrans
group by CoustomerID
having (Sum(case when Transactions = 'R' then T_No else 0 end) -
Sum(case when Transactions = 'D' then T_No else 0 end))>0

Simple query with left join cause ndb cluster timeout, but work fine on innodb

Recently I just move my database to ndb cluster, and I got database with around 200.000 record
I try to run this query to get monthly report, but always got query timeout in ndb cluster, when I try the query on the InnoDB it give fast query result < 1 Sec
this the query:
SELECT
m.merchant_name,
COUNT(CASE WHEN pay.payment_status = '00' THEN 1 ELSE NULL END) AS 'Success',
SUM(CASE WHEN pay.payment_status = '00' THEN pay.transaction_amount ELSE 0 END) AS 'Total success',
COUNT(CASE WHEN pay.payment_status != '00' THEN 1 ELSE NULL END) AS 'Fail',
SUM(CASE WHEN pay.payment_status != '00' THEN pay.transaction_amount ELSE 0 END) AS 'Total Fail',
COUNT(pay.trx_id) AS 'Total',
SUM(pay.transaction_amount) AS 'Total Amount'
FROM
(
SELECT
mchn.merchant_name,
mchl.channel_id
FROM
db_merchant mchn
LEFT JOIN db_merchant_channel mchl ON
mchl.merchant_id = mchn.merchant_id ) AS m
LEFT JOIN (
SELECT
x.trx_id,
x.channel_id,
fq.transaction_amount,
fq.transaction_status,
fs.payment_status
FROM
t_transaction x
LEFT JOIN flag_request fq ON
x.channel_id = fq.channel_id
AND x.transaction_no = fq.transaction_no
LEFT JOIN flag_response fs ON
fs.freq_id = fq.freq_id
WHERE
LEFT(DATE(fs.created_at),7) = '2020-03' ) AS pay ON
CONVERT(m.channel_id USING utf8) = CONVERT(pay.channel_id USING utf8)
GROUP BY
m.channel_id
explain result from ndb cluster
explain result from innodb
what's possibly wrong?
There are a lot of differences between NDB and InnoDB. Anyway, here are some things that make the queries inefficient:
This pattern is inefficient; see if you can reformulate it into something else:
FROM ( SELECT ... ) JOIN ( SELECT ... ) ON ...
Not sargable:
LEFT(DATE(fs.created_at),7) = '2020-03'
Change to
fs.created_at >= '2020-03-01'
AND fs.created_at < '2020-03-01' + INTERVAL 1 MONTH
Not sargable:
ON CONVERT(m.channel_id USING utf8) = CONVERT(pay.channel_id USING utf8)
Instead, make sure both are declared to use the same CHARACTER SET and COLLATION and do simply
ON m.channel_id = pay.channel_id
Please provide SHOW CREATE TABLE so we can discuss indexes.

Not able to alias column name in nested case using sql query

In this code its able to alias each case statement separately like,
SELECT
id,
SUM(CASE
WHEN (a.place = 'CHN' AND a.salary = 20000)
THEN '1'
ELSE '0'
END) AS '20K Salary',
SUM(CASE
WHEN (a.place = 'CHN' and a.salary = 35000)
THEN '1'
ELSE '0'
END) AS '35K Salary'
FROM Employee a;
but when nested CASE statement is used,
SELECT
id,
SUM(CASE
WHEN (a.place = 'CHN')
THEN (CASE
WHEN a.salary = 20000
THEN '1'
ELSE '0'
END) AS '20K Salary',
(CASE
WHEN a.salary = 35000
THEN '1'
ELSE '0'
END) AS '35K Salary'
END)
FROM Employee a;
its not possible to execute the query
In the first set of code each case statement is part of the SELECT list (i.e. they are in a comma separated list following SELECT) so each returns a column. In the second set of code there is only one case statement in the SELECT list, the fact that it is nested has no impact on this. Also the syntax for the nested case isn't correct because the THEN part is followed by two expressions separated by commas which is not allowed.
Of course this is possible to do what you want. You want to create two columns, so each needs its own logic and its own alias:
SELECT id,
SUM(CASE WHEN a.place = 'CHN' AND a.salary = 20000 THEN 1 ELSE 0
END) as Salary_20K,
SUM(CASE WHEN a.place = 'CHN' AND a.salary = 35000 THEN 1 ELSE 0
END) as Salary_35K
FROM Employee a;
Note: Don't put numeric constants in single quotes. Only use single quotes for string and date constants.

How do I calculate the difference of two alias for sorting

Considering the following code:
SELECT SUM(w.valor),
SUM(CASE WHEN w.tipo = '+' THEN w.valor ELSE 0 END) AS total_credit,
SUM(CASE WHEN w.tipo = '-' THEN w.valor ELSE 0 END) AS total_debit,
w.clientUNIQUE,
c.client as cclient
FROM wallet AS w
LEFT JOIN clients AS c ON w.clientUNIQUE = c.clientUNIQUE
WHERE w.status='V'
GROUP BY w.clientUNIQUE
ORDER BY total_credit-total_debit
I'm trying to calculate the difference of two aliased calculated values for sorting purposes, but I'm getting the following error:
Reference 'total_credit' not supported (reference to group function)
What am I doing wrong and how can I order results by using the difference value between the two aliases?
You can't refer to columns by their alias in the same select expression, so there are 2 options...
Repeat the expressions in the order by (yuk):
ORDER BY
SUM(CASE WHEN w.tipo = '+' THEN w.valor ELSE 0 END) AS total_credit -
SUM(CASE WHEN w.tipo = '-' THEN w.valor ELSE 0 END) AS total_debit
Or easier on the brain and easier to maintain (DRY), order via a sub query:
select * from (
<your query without the ORDER BY>
) q
ORDER BY total_credit - total_debit

Trying to COUNT the same table for different values

I have a table called flags from which I'm trying to extract two COUNTs.
I'd like one COUNT for the number of flags since the start of the year and a separate COUNT for this week's allocation.
The query I'm using is as follows:
SELECT
COUNT(f1.ID) AS `Total Flags`,
COUNT(f2.ID) AS `Weekly Flags`
FROM `frog_flags`.`flags` f1
LEFT JOIN `frog_flags`.`flags` f2
ON f1.`ID` = f2.`ID`
WHERE
f2.`Datetime` > '2013-07-08 00:00:00'
AND
( f1.`Staff_ID` = '12345' AND f2.`Staff_ID` = '12345')
AND
f1.`Datetime` > '2012-09-01 00:00:00'
Even though I have data in place, it's showing 0 for both the Total Flags and the Weekly Flags.
I suspect I've confused my WHERE clauses for trying to JOIN the same table twice.
Am I using my clauses incorrectly when trying to COUNT the same table for different values?
This is a cross-tab SQL query - it's a great design pattern once you get the hang of it:
SELECT
sum( case when `Datetime`> '2012-09-01 00:00:00' then 1 else 0 end) AS `Total Flags`,
sum( case when `Datetime`> '2013-07-08 00:00:00' then 1 else 0 end) AS `Weekly Flags`
FROM `frog_flags`.`flags` f1
WHERE f1.`Staff_ID` = '12345'
You use a condition to create basically boolean flags which get summed up - this allows for a number of predefined new columns instead of rows.
You could take it further and do it for all staff simultaneously:
SELECT
f1.`Staff_ID`,
sum( case when `Datetime`> '2012-09-01 00:00:00' then 1 else 0 end) AS `Total Flags`,
sum( case when `Datetime`> '2013-07-08 00:00:00' then 1 else 0 end) AS `Weekly Flags`
FROM `frog_flags`.`flags` f1
WHERE f1.`Staff_ID` = '12345'
GROUP BY f1.`Staff_ID`