I have a SQL query which takes user inputs hence security flaw is present.
The existing query is:
SELECT BUS_NM, STR_ADDR_1, CITY_NM, STATE_CD, POSTAL_CD, COUNTRY_CD,
BUS_PHONE_NB,PEG_ACCOUNT_ID, GDN_ALERT_ID, GBIN, GDN_MON_REF_NB,
ALERT_DT, ALERT_TYPE, ALERT_DESC,ALERT_PRIORITY
FROM ( SELECT A.BUS_NM, AE.STR_ADDR_1, A.CITY_NM, A.STATE_CD, A.POSTAL_CD,
CC.COUNTRY_CD, A.BUS_PHONE_NB, A.PEG_ACCOUNT_ID, 'I' ||
LPAD(INTL_ALERT_DTL_ID, 9,'0') GDN_ALERT_ID,
LPAD(IA.GBIN, 9,'0') GBIN, IA.GDN_MON_REF_NB,
DATE(IAD.ALERT_TS) ALERT_DT,
XMLCAST(XMLQUERY('$A/alertTypeConfig/biqCode/text()' passing
IAC.INTL_ALERT_TYPE_CONFIG as "A") AS CHAR(4)) ALERT_TYPE,
, ROW_NUMBER() OVER () AS "RN"
FROM ACCOUNT A, Other tables
WHERE IA.GDN_MON_REF_NB = '100'
AND A.PEG_ACCOUNT_ID = IAAR.PEG_ACCOUNT_ID
AND CC.COUNTRY_CD = A.COUNTRY_ISO3_CD
ORDER BY IA.INTL_ALERT_ID ASC )
WHERE ALERT_TYPE IN (" +TriggerType+ ");
I changed it to accept TriggerType from setString like:
SELECT BUS_NM, STR_ADDR_1, CITY_NM, STATE_CD, POSTAL_CD, COUNTRY_CD,
BUS_PHONE_NB,PEG_ACCOUNT_ID, GDN_ALERT_ID, GBIN, GDN_MON_REF_NB,
ALERT_DT, ALERT_TYPE, ALERT_DESC,ALERT_PRIORITY
FROM ( SELECT A.BUS_NM, AE.STR_ADDR_1, A.CITY_NM, A.STATE_CD, A.POSTAL_CD,
CC.COUNTRY_CD, A.BUS_PHONE_NB, A.PEG_ACCOUNT_ID,
'I' || LPAD(INTL_ALERT_DTL_ID, 9,'0') GDN_ALERT_ID,
LPAD(IA.GBIN, 9,'0') GBIN, IA.GDN_MON_REF_NB,
DATE(IAD.ALERT_TS) ALERT_DT,
XMLCAST(XMLQUERY('$A/alertTypeConfig/biqCode/text()' passing
IAC.INTL_ALERT_TYPE_CONFIG as "A") AS CHAR(4)) ALERT_TYPE,
ROW_NUMBER() OVER () AS "RN"
FROM ACCOUNT A, other tables
WHERE IA.GDN_MON_REF_NB = '100'
AND A.PEG_ACCOUNT_ID = IAAR.PEG_ACCOUNT_ID
AND CC.COUNTRY_CD = A.COUNTRY_ISO3_CD
ORDER BY IA.INTL_ALERT_ID ASC )
WHERE ALERT_TYPE IN (?);
Setting trigger type as below:
if (StringUtils.isNotBlank(request.getTriggerType())) {
preparedStatement.setString(1, triggerType != null ? triggerType.toString() : "");
}
Getting error as
Caused by: com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.19.26
The -302 SQLCODE indicates a conversion error of some sort.
SQLSTATE 22001 narrows that down a bit by telling us that you are trying to force a big string into a small variable. Given the limited information in your question, I am guessing it is the XMLCAST that is the culprit.
DB2 won't jam 30 pounds of crap into a 4 pound bag so to speak, it gives you an error. Maybe giving XML some extra room in the cast might be a help. If you need to make sure it ends up being only 4 characters long, you could explicitly do a LEFT(XMLCAST( ... AS VARCHAR(64)), 4). That way the XMLCAST has the space it needs, but you cut it back to fit your variable on the fetch.
The other thing could be that the variable being passed to the parameter marker is too long. DB2 will guess the type and length based on the length of ALERT_TYPE. Note that you can only pass a single value through a parameter marker. If you pass a comma separated list, it will not behave as expected (unless you expect ALERT_TYPE to also contain a comma separated list). If you are getting the comma separated list from a table, you can use a sub-select instead.
Wrong IN predicate use with a parameter.
Do not expect that IN ('AAAA, M250, ABCD') (as you try to do passing a comma-separated string as a single parameter) works as IN ('AAAA', 'M250', 'ABCD') (as you need). These predicates are not equivalent.
You need some "string tokenizer", if you want to pass such a comma-separated string like below.
select t.*
from
(
select XMLCAST(XMLQUERY('$A/alertTypeConfig/biqCode/text()' passing IAC.INTL_ALERT_TYPE_CONFIG as "A") AS CHAR(4)) ALERT_TYPE
from table(values xmlparse(document '<alertTypeConfig><biqCode>M250, really big code</biqCode></alertTypeConfig>')) IAC(INTL_ALERT_TYPE_CONFIG)
) t
--WHERE ALERT_TYPE IN ('AAAA, M250, ABCD')
join xmltable('for $id in tokenize($s, ",\s?") return <i>{string($id)}</i>'
passing cast('AAA, M250 , ABCD' as varchar(200)) as "s"
columns token varchar(200) path '.') x on x.token=t.ALERT_TYPE
;
Run the statement as is. Then you may uncomment the string with WHERE clause and comment out the rest to see what you try to do.
P.S.:
The error you get is probably because you don't specify the data type of the parameter (you don't use something like IN (cast(? as varchar(xxx))), and db2 compiler assumes that its length is equal to the length of the ALERT_TYPE expression (4 bytes).
Running a big query Select Case When query from the command line. When looking in a string, for a numeric value and casting that to an integer - this needs to be compared to a value and return a boolean so that the case statement worked.
bq query SELECT case when integer(right(strWithNumb,8))> 10000000 then right(strWithNumb,8) else "no" end FROM [Project:bucket.mytable]
returned
"CASE expects the WHEN expression to be boolean."
I tried:
boolean(integer(right(strWithNumb,8))> 10000000)
but got
" Was expecting: "WHEN" ..."
Even though your original query works in Web UI - it DOES fail in bq command line tool depends on your environment - for example if you are on PC
Try to escape > character with ^ and embrace whole query with " as it is in example below. Please note also escaping of " in "no"
bq query "SELECT case when integer(right(strWithNumb,8)) ^> 10000000 then right(strWithNumb,8) else \"no\" end FROM [Project:bucket.mytable]"
you can avoid later by changing " to '
bq query "SELECT case when integer(right(strWithNumb,8)) ^> 10000000 then right(strWithNumb,8) else 'no' end FROM [Project:bucket.mytable]"
A little more explanations:
when you execute your original command (on PC for example via Google Cloud SDK Shell) your actual query becomes as below
SELECT case when integer(right(strWithNumb,8)) then right(strWithNumb,8) else "no" end FROM [Project:bucket.mytable]
As you can see your > 10000000 part of query gets lost thus making WHEN expression INTEGER instead of expected BOOLEAN
Hope this helped
I have a simple CASE statement where in my ELSE block numeric column I want to display as '-'.
But it gives me an error
Arithmetic overflow error converting varchar to data type numeric.
How would I do that?
I want it like this:
SELECT
CASE WHEN ChargeName = 'Premium' THEN CompanyCommissionPercentage ELSE '-' END AS CompanyCommissionPercentage
,CASE WHEN ChargeName = 'Premium' THEN RemitterCommissionPercentage ELSE '-' END AS RemitterCommissionPercentage
,CASE WHEN ChargeName = 'Premium' THEN RemitterCommission ELSE '-'END AS RemitterCommission
,CASE WHEN ChargeName = 'Premium' THEN GrossCommission ELSE '-'END AS GrossCommission
FROM #tmpAccountsPayable
`SELECT
CASE WHEN ChargeName = 'Premium' THEN CAST(CompanyCommissionPercentage as varchar(10)) ELSE CAST('-' as varchar(10)) END AS CompanyCommissionPercentage
FROM #tmpAccountsPayable`
Here's a picture of where in excel you can set formatting to a -
You may be better off passing in a zero instead of the dash and allowing excel formatting to make the 0 a - (assuming of course the output is going into excel)
Notice below in E20 the 0 value is converted to a - when accounting format (comma format) is used.
Also notice how a regular dash is left aligned while the accounting - is indented.
My assumption was that it would return a true if that value was numeric (within the isnumeric range) but FALSE if the ISNULL returns 'blah'. Seems like my assumption was off...
I'm using the it in the following way
case when ISNULL(ISNUMERIC(c.npinumber), 'blah') = 1
then c.NPiNUmber
else 'not valid: ' + c.NpiNumber
end as npi
Building on Dhruvesh's answer,
case
when ISNUMERIC(c.npinumber) = 1 then c.NPiNUmber
else 'not valid: ' + c.NpiNumber
end as npi
Will produce NULL anytime NpiNumber is NULL. The reason is that NULL + any string will still return NULL. The solution is to simply use the COALESCE function
case
when ISNUMERIC(c.npinumber) = 1 then c.NPiNUmber
else 'not valid: ' + COALESCE(c.NpiNumber, 'NULL VALUE')
end as npi
select ISNUMERIC(ISNULL(NULL, 'blah')),
ISNUMERIC(ISNULL(1234, 'blah')),
ISNUMERIC(ISNULL('ab', 'blah'))
Returns 0, 1, 0 - so your logic is correct.
When SQL's not behaving I like to simplify my query. Try running the query without your case statement first. If the results look right, then add additional logic.
What collation is your database? It's always a good idea to keep your column names properly cased (I'm looking at that all-lowercase column name over there...).
You don't require ISNULL. ISNUMERIC will return 1 if it's numberic or 0 if it's NULL or non-numeric.
case
when ISNUMERIC(c.NpiNumber) = 1 then c.NPiNUmber
else 'not valid: ' + c.NpiNumber
end as npi
Also as Euric Mentioned you may want to look at your all-lowercase column name.
Can anyone tell me how to translate the following T-SQL statement:
SELECT fileld1 = CASE
WHEN T.option1 THEN -1
ELSE
CASE WHEN T.option2 THEN 0
ELSE 1
END
END
FROM Table1 AS T
The point is I need to validate two different options from the table for a single field in the select statement..
I have tried to do somthing with an IF statement in pl/sql, but it just doesnt work for me:
SELECT IF T.option1 THEN -1
ELSE IF T.option2 THEN 0
ELSE 1
END
FROM Table1 AS T
I am not actually sure how to write IF statement inside the SELECT statement..
And also, I need to do it INSIDE the select statement because I am constructing a view.
Use:
SELECT CASE
WHEN T.option1 = ? THEN -1
WHEN T.option2 = ? THEN 0
ELSE 1
END AS field1
FROM Table1 AS T
I can't get your original TSQL to work - I get:
Msg 4145, Level 15, State 1, Line 4
An expression of non-boolean type specified in a context where a condition is expected, near 'THEN'.
...because there's no value evaluation. If you're checking if the columns are null, you'll need to use:
SELECT CASE
WHEN T.option1 IS NULL THEN -1
WHEN T.option2 IS NULL THEN 0
ELSE 1
END AS field1
FROM Table1 AS T
...or if you need when they are not null:
SELECT CASE
WHEN T.option1 IS NOT NULL THEN -1
WHEN T.option2 IS NOT NULL THEN 0
ELSE 1
END AS field1
FROM Table1 AS T
CASE expressions shortcircuit - if the first WHEN matches, it returns the value & exits handling for that row - so the options afterwards aren't considered.
If I remember correctly, PL/SQL also supports the case. You just would have to move the column alias from "field1=" before the expression to "AS filed1" after the expression.