SQL Error Converting Data to Int When I am Not Asking It To - sql

I have the following SQL statement. In it I need to convert some numbers stored as varchar to decimal in order to sum them.
When I run this SQL against my constraints I get this message:
Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the varchar value '1635.34' to data
type int.
Which baffles me because I am casting my data as decimal. It also baffles me because when I use different constraints that have the same type of data in the field (1234.56 type of format) it works. That data is in the TotalPremium field.
(My logic is a bit complex so that is why SQL statement is complex. I am posting all of it for clarity sake. Also, redesigning database table field type is not an option at this point.)
SELECT Account_No, version_num, LineOfBus, ProductNo, QuoteNo, Sum(Cast(TotalPremium as Decimal(16,2))) TotalPremium
FROM
(SELECT t.Account_No, t.version_num,
CASE
WHEN t.PackageIndicator = '1' THEN 'Package' Else t.Lob
END AS LineOfBus,
t.ProductNo, t.QuoteNo, Cast(COALESCE(t.TotalPremium,0) as decimal(16,2)) TotalPremium
FROM uAccountProductInfo as T
WHERE t.version_num IN
(SELECT sqVersionNumber.version_num
FROM
/* this captures unique package product records (or just stand alone records as well) */
(SELECT DISTINCT sqUnique.version_num, Count(sqUnique.version_num) VersionCount
FROM
/* grab list of all uniquer version, product, quote combinations (use distinct to combine package */
(SELECT DISTINCT version_num, productNo, quoteNo
FROM uAccountProductInfo
WHERE Account_No = '1172014' /* pass as parameter */
AND ProductNo IN ('6472930', '6474927') /* pass as parameter */
AND QuoteNo IN ('724185-01', '881957-08') /* pass as parameter */
) AS sqUnique
GROUP BY version_num
HAVING Count(version_num) = 2 /* pass as variable based on number of products, quotes */
) as sqVersionNumber
)
AND t.Account_no = '1172014' /* pass as parameter */
AND t.ProductNo IN ('6472930', '6474927') /* pass as parameter */
AND t.QuoteNo IN ('724185-01', '881957-08') /* pass as parameter */) as sqLOB
GROUP BY Account_No, version_num, LineOfBus, ProductNo, QuoteNo

The problem is that SQL Server does not guarantee the order of evaluation of operations. You clearly have something improper in the field. In SQL Server 2012+, use try_convert():
SELECT Sum(try_convert(decimal(16, 2), TotalPremium ))) as TotalPremium
In earlier versions, use case:
SELECT Sum(case when isnumeric(TotalPremium) = 1 then convert(decimal(16, 2), TotalPremium)) end) as TotalPremium
isnumeric() is not perfect, but it should be good enough for your purposes.

Cast t.TotalPremium to decimal before coalescing. Your query is doing coalesce on a string and an integer, then casting the result to decimal. Try using0.0instead of0as well.
edit I do not actually think using 0.0 rather than 0 is a good idea, aside from readability. If that is the goal, cast it to the same decimal datatype. Otherwise, this could be construed as a datatype dominant over decimal. 0 as int or varchar should not take precedence over our value casted to a decimal.

You could use isnull() instead of coalesce(), though it would still be better practice to use the same datatype as RexMaison points out.
create table t (TotalPremium varchar(16));
insert into t values (''),(null),('1635.34');
/* no error */
select isnull(t.TotalPremium,0)
from t;
/* no error */
select coalesce(t.TotalPremium,'0')
from t;
/* error */
select coalesce(t.TotalPremium,0)
from t;
rextester demo: http://rextester.com/OHEJ71310

Just posting final code that worked after incorporating elements of all 3 answers.
SELECT Account_No, version_num, LineOfBus, ProductNo, QuoteNo,
SUM(CASE
WHEN ISNUMERIC(TotalPremium) = 1 THEN CONVERT(decimal(16,2),TotalPremium)
END) As TotalPremium
FROM
(SELECT t.Account_No, t.version_num,
CASE
WHEN ISNull(t.PackageIndicator,'0') = '1' THEN 'Package' Else t.Lob
END AS LineOfBus,
t.ProductNo, t.QuoteNo,
ISNull(CASE
WHEN ISNUMERIC(t.TotalPremium) = 1 THEN CONVERT(decimal(16,2),t.TotalPremium)
END, 0) TotalPremium
FROM uAccountProductInfo as T
WHERE t.version_num IN
(SELECT sqVersionNumber.version_num
FROM
/* this captures unique package product records (or just stand alone records as well) */
(SELECT DISTINCT sqUnique.version_num, Count(sqUnique.version_num) VersionCount
FROM
/* grab list of all uniquer version, product, quote combinations (use distinct to combine package */
(SELECT DISTINCT version_num, productNo, quoteNo
FROM uAccountProductInfo
WHERE Account_No = '1172014' /* pass as parameter */
AND ProductNo IN ('6472930', '6474927') /* pass as parameter */
AND QuoteNo IN ('724185-01', '881957-08') /* pass as parameter */
) AS sqUnique
GROUP BY version_num
HAVING Count(version_num) = 2 /* pass as variable based on number of products, quotes */
) as sqVersionNumber
)
AND t.Account_no = '1172014' /* pass as parameter */
AND t.ProductNo IN ('6472930', '6474927') /* pass as parameter */
AND t.QuoteNo IN ('724185-01', '881957-08') /* pass as parameter */) as sqLOB
GROUP BY Account_No, version_num, LineOfBus, ProductNo, QuoteNo

Related

How to calculate superscript values in SQL

I have prices coming in my source file like below -
78-22¼,
78-18⅝
I need to calculate these price. For example for first case result should be 78-22.25. I searched a lot but found that SQL supports few of these characters only. Is there anyway to make sure we are able to calculate for whatever value we are getting. Solution in either SQL or PowerShell could work.
You could write a PowerShell function to convert the fractions to decimals:
PS ~> ConvertTo-Decimal '18⅝'
18.625
To do so, we'll need to write a function that:
Uses regex to identify and extract the integer and fraction parts
Uses [char]::GetNumericValue() to get the decimal representation of the fraction
Outputs the sum of the two
function ConvertTo-Decimal {
param(
[Parameter(Mandatory)]
[string]$InputObject
)
if($InputObject -match '^(-?)(\d+)(\p{No})?$'){
$baseValue = +$Matches[2]
if($Matches[3]){
$baseValue += [char]::GetNumericValue($Matches[3])
}
if($Matches[1] -eq '-'){
$baseValue *= -1
}
return $baseValue
}
return 0
}
Hoo this one was fun.
If you want to do it purley in TSQL give this a tug:
DECLARE #table TABLE (Glyph NVARCHAR(2), Dec DECIMAL(8,6))
INSERT INTO #table (Glyph, Dec) VALUES
(N'¼', 1.0/4),(N'½', 1.0/2),(N'¾', 3.0/4),(N'⅐', 1.0/7),
(N'⅑', 1.0/8),(N'⅒',1.0/10),(N'⅓', 1.0/3),(N'⅔', 2.0/3),
(N'⅕', 1.0/5),(N'⅖', 2.0/5),(N'⅗', 3.0/5),(N'⅘', 4.0/5),
(N'⅙', 1.0/6),(N'⅚', 5.0/6),(N'⅛', 1.0/8),(N'⅜', 3.0/8),
(N'⅝', 5.0/8),(N'⅞', 7.0/8),(N'⅟', 1.0/1)
DECLARE #values TABLE (ID INT IDENTITY, value NVARCHAR(20))
INSERT INTO #values (value) VALUES
(N'78-22¼'),(N'78-18⅝'),(N'10+1')
;WITH sort AS (
SELECT v.*, t.*,
CASE WHEN m.value = v.value THEN
CASE WHEN t.Dec IS NOT NULL THEN REPLACE(p.value,t.Glyph,'')+dec
ELSE p.value
END
ELSE
CASE WHEN t.Dec IS NOT NULL THEN REPLACE(m.value,t.Glyph,'')+dec
ELSE m.value
END
END AS v,
CASE WHEN m.value = v.value THEN '+'
ELSE '-' END AS op,
ROW_NUMBER() OVER (PARTITION BY v.value ORDER BY CASE WHEN m.value = v.value THEN CHARINDEX(m.value,v.value) ELSE CHARINDEX(p.value,v.value) END) AS subID
FROM #values v
OUTER APPLY STRING_SPLIT(v.value,'-') m
OUTER APPLY STRING_SPLIT(v.value,'+') p
LEFT OUTER JOIN #table t
ON RIGHT(CASE WHEN m.value = v.value THEN p.value ELSE m.value END,1) = t.Glyph
)
SELECT ID, value, SUM(v * CASE WHEN subId = 1 THEN 1 WHEN op = '+' THEN 1 ELSE -1 END) AS v
FROM sort
GROUP BY ID, value
ID value v
---------------------
1 78-22¼ 55.750000
2 78-18⅝ 59.375000
3 10+1 11.000000
#values replaces your table.
disclaimer: this works, it'll probably perform like hot garbage, but it works :P
In T-SQL you could write a function like this that takes a vulgar fraction and replaces it with its decimal equivalent (this is not completely exhaustive, but handles the most common fractions, and makes a guess about whether you want .666 or .667 or something else for ⅔):
CREATE FUNCTION dbo.FractionToDecimal(#str nvarchar(255))
RETURNS TABLE
AS
RETURN
(
SELECT str = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
REPLACE(REPLACE(REPLACE(REPLACE(#str, N'¼','.25'),
N'½','.5'), N'¾','.75'), N'⅓','.333'), N'⅔','.666'),
N'⅛','.125'), N'⅜','.375'), N'⅝','.625'), N'⅞','.875')
);
Sample usage:
DECLARE #x table(str nvarchar(255));
INSERT #x VALUES(N'78-22¼'),(N'78-18⅝');
SELECT [input] = i.str, [output] = o.str
FROM #x AS i
CROSS APPLY dbo.FractionToDecimal(str) AS o;
Output:
input
output
78-22¼
78-22.25
78-18⅝
78-18.625
Working example in this fiddle.
Note there are only so many fraction codes available that you could be pulling in ... so you could add any to the above e.g. from this set but it isn't the case that you would have to handle any possible fraction, only the ones that are represented by these specific symbols. If someone passes in plain text 9/10 or 31/33 that is a completely different problem space than what you have outlined in the question.

Declare variables in scheduled query BigQuery;

I am developing a scheduled query where I am using the WITH statement to join and filtrate several tables from BigQuery. To filtrate the dates, I would like to declare the following variables:
DECLARE initial, final DATE;
SET initial = DATE_TRUNC(DATE_TRUNC(CURRENT_DATE(), MONTH)+7,ISOWEEK);
SET final = LAST_DAY(DATE_TRUNC(CURRENT_DATE(), MONTH)+7, ISOWEEK);
However, when executing this query, I am getting two results; one for the variables declared (which I am not interested in having them as output), and the WITH statement that is selected at the end (which as the results that I am interested in).
The principal problem is that, whenever I try t connect this scheduled query to a table in Google Data Studio I get the following error:
Invalid value: configuration.query.destinationTable cannot be set for scripts;
How can I declare a variable without getting it as a result at the end?
Here you have a sample of the code I am trying work in:
DECLARE initial, final DATE;
SET initial = DATE_TRUNC(DATE_TRUNC(CURRENT_DATE(), MONTH)+7,ISOWEEK);
SET final = LAST_DAY(DATE_TRUNC(CURRENT_DATE(), MONTH)+7, ISOWEEK);
WITH HelloWorld AS (
SELECT shop_date, revenue
FROM fulltable
WHERE shop_date >= initial
AND shop_date <= final
)
SELECT * from HelloWorld;
with initial1 as ( select DATE_TRUNC(DATE_TRUNC(CURRENT_DATE(), MONTH)+7,ISOWEEK) as initial2),
final1 as ( select LAST_DAY(DATE_TRUNC(CURRENT_DATE(), MONTH)+7, ISOWEEK) as final2),
HelloWorld AS (
SELECT shop_date, revenue
FROM fulltable
WHERE shop_date >= (select initial2 from initial1) AND shop_date <= (select final2 from final1)
)
SELECT * from HelloWorld;
With config table having just 1 row and cross-joining it with your table, your query can be written like below.
WITH config AS (
SELECT DATE_TRUNC(DATE_TRUNC(CURRENT_DATE(), MONTH)+7,ISOWEEK) AS initial,
LAST_DAY(DATE_TRUNC(CURRENT_DATE(), MONTH)+7, ISOWEEK) AS final
),
HelloWorld AS (
SELECT * FROM UNNEST([DATE '2022-06-06']) shop_date, config
WHERE shop_date >= config.initial AND shop_date <= config.final
)
SELECT * FROM HelloWorld;
A few patterns I've used:
If you have many that have the same return type (STRING)
CREATE TEMP FUNCTION config(key STRING)
RETURNS STRING AS (
CASE key
WHEN "timezone" THEN "America/Edmonton"
WHEN "something" THEN "Value"
END
);
Then use config(key) to retrieve the value.
Or,
Create a function for each constant
CREATE TEMP FUNCTION timezone()
RETURNS STRING AS ("America/Edmonton");
Then use timezone() to get the value.
It would execute the function each time, so don't do something expensive in there (like SELECT from another table).

DB2 select ... insert fails converting a leap day into a date

I am attempting to do a select insert which takes a DECIMAL(8,0) representation of a date (DOB), converts it into a date, and inserts it into another table.
INSERT INTO myschema.beneficiary_info
(name, address, city, state, zip, dob, spouse)
SELECT
jh.bname, jh.badd1, jh.bcity, jh.bstate, jh.bzip,
CASE
WHEN JH.BDOB8 != '0' AND JH.BDOB8 IS NOT NULL THEN
DATE(
TIMESTAMP_FORMAT(
CHAR(jh.bdob8) ,'YYYYMMDD'))
ELSE null
END,
--jh.bdob8,
jh.bspous
FROM TABLE(MYSCHEMA.REMOTE_TABLE()) JH -- function pointing to a remote database
But, about 5,000 records into it (having successfully processed dates and nulls), it fails with
[Code: -181, SQL State: 22007] [SQL0181] Value in date, time, or timestamp string not valid.
I narrowed the data down to the offending row, and found this (showing results of case statement and the actual bdob8 field:
0006 bdob8
1958-12-24 19581224
(null) 19620229
1965-02-07 19650207
The leap day appears to be causing the select ... insert to fail.
At this point, the case statement has already successfully navigated nulls by simply passing the null to the insert. Yet for some reason, when the date/timestamp functions barf and return a null, the whole thing breaks.
Looking for ideas how to overcome the apparent inability to handle leap days...
(Using IBMi DB2 V7R3M0 L00)
As Gordon pointed out, 1962 isn't a leap year.
I'd suggest building your own User Defined Function (UDF) that does the date conversions...
That way you'll be in control of what's returned for invalid dates. You can also handle common numeric special values (or return null)
exmaple
00000000 --> 0001-01-01
99999999 --> 9999-12-31
There's a popular open source package of UDF's available, iDate by Alan Campin, that would make a great starting place for your own UDF.
Use a UDF to filter bad data
CREATE FUNCTION ASDATE (
INPUTDATESTR VARCHAR(10) )
RETURNS DATE
LANGUAGE SQL
SPECIFIC ASDATE
NOT DETERMINISTIC
MODIFIES SQL DATA
CALLED ON NULL INPUT
CONCURRENT ACCESS RESOLUTION DEFAULT
SET OPTION ALWBLK = *ALLREAD ,
ALWCPYDTA = *OPTIMIZE ,
COMMIT = *NONE ,
DECRESULT = (31, 31, 00) ,
DYNDFTCOL = *NO ,
DYNUSRPRF = *USER ,
SRTSEQ = *HEX
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION RETURN NULL ;
RETURN DATE ( TIMESTAMP_FORMAT ( CHAR ( INPUTDATESTR ) , 'YYYYMMDD' ) ) ;
END ;
It is accessed like this:
INSERT INTO myschema.beneficiary_info
(name, address, city, state, zip, dob, spouse)
SELECT
jh.bname, jh.badd1, jh.bcity, jh.bstate, jh.bzip,
CASE WHEN ASDATE(jh.bdob8) IS NOT NULL THEN ASDATE(jh.bdob8) ELSE NULL END
--jh.bdob8,
jh.bspous
FROM TABLE(MYSCHEMA.REMOTE_TABLE()) JH -- function pointing to a remote database
Many thanks to Charles' pointing me in the right direction, and https://stackoverflow.com/a/39683452/2129574
The options in the UDF are the defaults that IBM Navigator for i filled in; any comments about improvements to the function are welcomed.

"Insert Into Select" writing to table but contains sub-query reading from same table

I am adding records into my table "SampleTestLimits" using an "Insert Into Select", but which also has a sub-query reading from the same table to perform a count for me.
I don't think the sub-query is seeing the earlier records added by my "Insert Into Select". It's the same for Oracle and SQL Server. The code for SQL Server is shown below (my sub-query begins with "SELECT COALESCE...").
I have another stored procedure which does work in a similar situation.
Would appreciate it if anybody could tell if what I'm doing is a no no.
ALTER PROCEDURE [dbo].[CreateSampleTestLimits]
#SampleCode as NVARCHAR(80),
#TestPosition as smallint,
#TestCode NVARCHAR(20),
#TestVersion smallint,
#EnterDate as integer,
#EnterTime as smallint,
#EnterUser as NVARCHAR(50)
AS
BEGIN
INSERT INTO SampleTestLimits
([AuditNumber]
,[LimitNumber]
,[ComponentRow]
,[ComponentColumn]
,[ComponentName]
,[TestPosition]
,[SampleCode]
,[AuditFlag]
,[LimitSource]
,[LimitType]
,[UpperLimitEntered]
,[UpperLimitValue]
,[LowerLimitEntered]
,[LowerLimitValue]
,[LimitTextColour]
,[LimitPattern]
,[LimitForeColour]
,[LimitBackColour]
,[CreatedDate]
,[CreatedTime]
,[CreatedUser]
,[LimitText]
,[FilterName]
,[deleted]
,IsRuleBased)
SELECT 1 --starting auditnumber
,(SELECT COALESCE(MAX(LimitNumber), 0) + 1 AS NextLimitNumber FROM SampleTestLimits WHERE SampleCode=#SampleCode AND TestPosition=#TestPosition AND ComponentRow=1 AND ComponentColumn=1 AND AuditFlag=0) -- TFS bug# 3952: Calculate next limit number.
,ComponentRow
,ComponentColumn
,(select ComponentName from TestComponents TC where TC.TestCode=#TestCode and TC.ComponentColumn=TestLimits.ComponentColumn and TC.ComponentRow = TestLimits.ComponentRow and TC.AuditNumber=TestLimits.AuditNumber)
,#TestPosition
,#SampleCode
,0 --auditflag
,1 --limitsource = test
,[LimitType]
,[UpperLimitEntered]
,[UpperLimitValue]
,[LowerLimitEntered]
,[LowerLimitValue]
,[LimitTextColour]
,[LimitPattern]
,[LimitForeColour]
,[LimitBackColour]
,#EnterDate
,#EnterTime
,#EnterUser
,[LimitText]
,[FilterName]
,0 --deleted
,0 --rule based
FROM TestLimits join Tests on Tests.TestCode=TestLimits.TestCode and Tests.AuditNumber= TestLimits.AuditNumber WHERE Tests.TestCode=#TestCode and Tests.auditnumber=#TestVersion and ([TestLimits].FilterString is null or DATALENGTH([TestLimits].FilterString)=0)
END
Assuming that I understand your logic correctly (ie. that you want the nextlimitnumber to increase by 1 for each row being added), in Oracle, I'd do it by using the analytic function row_number() to work out what number to add to the previous max value, something like:
INSERT INTO sampletestlimits (auditnumber,
limitnumber,
componentrow,
componentcolumn,
componentname,
testposition,
samplecode,
auditflag,
limitsource,
limittype,
upperlimitentered,
upperlimitvalue,
lowerlimitentered,
lowerlimitvalue,
limittextcolour,
limitpattern,
limitforecolour,
limitbackcolour,
createddate,
createdtime,
createduser,
limittext,
filtername,
deleted,
isrulebased)
SELECT 1, --starting auditnumber
(SELECT COALESCE (MAX (limitnumber), 0) + 1 AS nextlimitnumber
FROM sampletestlimits
WHERE samplecode = p_samplecode
AND testposition = p_testposition
AND componentrow = 1
AND componentcolumn = 1
AND auditflag = 0)
+ row_number() over (partition by testposition, componentrow, componentcolumn, auditflag) as nextlimitnumber, -- TFS bug# 3952: Calculate next limit number.
componentrow,
componentcolumn,
(SELECT componentname
FROM testcomponents tc
WHERE tc.testcode = p_testcode
AND tc.componentcolumn = testlimits.componentcolumn
AND tc.componentrow = testlimits.componentrow
AND tc.auditnumber = testlimits.auditnumber),
p_testposition,
p_samplecode,
0, --auditflag
1, --limitsource = test
limittype,
upperlimitentered,
upperlimitvalue,
lowerlimitentered,
lowerlimitvalue,
limittextcolour,
limitpattern,
limitforecolour,
limitbackcolour,
p_enterdate,
p_entertime,
p_enteruser,
limittext,
filtername,
0, --deleted
0 --rule based
FROM testlimits
JOIN tests
ON tests.testcode = testlimits.testcode
AND tests.auditnumber = testlimits.auditnumber
WHERE tests.testcode = p_testcode
AND tests.auditnumber = p_testversion
AND ( testlimits.filterstring IS NULL
OR datalength (testlimits.filterstring) = 0);
I had to guess at what the partition by clause would need to contain - adjust that as necessary for your requirements.

Error creating function in DB2 with params

I have a problem with a function in db2
The function finds a record, and returns a number according to whether the first and second recorded by a user
The query within the function is this
SELECT
CASE
WHEN NUM IN (1,2) THEN 5
ELSE 2.58
END AS VAL
FROM (
select ROW_NUMBER() OVER() AS NUM ,s.POLLIFE
from LQD943DTA.CAQRTRML8 c
INNER JOIN LSMODXTA.SCSRET s ON c.MCCNTR = s.POLLIFE
WHERE s.NOEMP = ( SELECT NOEMP FROM LSMODDTA.LOLLM04 WHERE POLLIFE = '0010111003')
) AS T WHERE POLLIFE = '0010111003'
And works perfect
I create the function with this code
CREATE FUNCTION LIBWEB.BNOWPAPOL(POL CHAR)
RETURNS DECIMAL(7,2)
LANGUAGE SQL
NOT DETERMINISTIC
READS SQL DATA
RETURN (
SELECT
CASE
WHEN NUM IN (1,2) THEN 5
ELSE 2.58
END AS VAL
FROM (
select ROW_NUMBER() OVER() AS NUM ,s.POLLIFE
from LQD943DTA.CAQRTRML8 c
INNER JOIN LSMODXTA.SCSRET s ON c.MCCNTR = s.POLLIFE
WHERE s.NOEMP = ( SELECT NOEMP FROM LSMODDTA.LOLLM04 WHERE POLLIFE = POL)
) AS T WHERE POLLIFE = POL
)
The command runs executed properly
WARNING: 17:55:40 [CREATE - 0 row(s), 0.439 secs] Command processed.
No rows were affected
When I want execute the query a get a error
SELECT LIBWEB.BNOWPAPOL('0010111003') FROM DATAS.DUMMY -- dummy has only one row
I get
[Error Code: -204, SQL State: 42704] [SQL0204] BNOWPAPOL in LIBWEB
type *N not found.
I detect, when I remove the parameter the function works fine!
With this code
CREATE FUNCTION LIBWEB.BNOWPAPOL()
RETURNS DECIMAL(7,2)
LANGUAGE SQL
NOT DETERMINISTIC
READS SQL DATA
RETURN (
SELECT
CASE
WHEN NUM IN (1,2) THEN 5
ELSE 2.58
END AS VAL
FROM (
select ROW_NUMBER() OVER() AS NUM ,s.POLLIFE
from LQD943DTA.CAQRTRML8 c
INNER JOIN LSMODXTA.SCSRET s ON c.MCCNTR = s.POLLIFE
WHERE s.NOEMP = ( SELECT NOEMP FROM LSMODDTA.LOLLM04 WHERE POLLIFE = '0010111003')
) AS T WHERE POLLIFE = '0010111003'
)
Why??
This statement:
SELECT LIBWEB.BNOWPAPOL('0010111003') FROM DATAS.DUMMY
causes this error:
[Error Code: -204, SQL State: 42704] [SQL0204] BNOWPAPOL in LIBWEB
type *N not found.
The parm value passed into the BNOWPAPOL() function is supplied as a quoted string with no definition (no CAST). The SELECT statement assumes that it's a VARCHAR value since different length strings might be given at any time and passes it to the server as a VARCHAR.
The original function definition says:
CREATE FUNCTION LIBWEB.BNOWPAPOL(POL CHAR)
The function signature is generated for a single-byte CHAR. (Function definitions can be overloaded to handle different inputs, and signatures are used to differentiate between function versions.)
Since a VARCHAR was passed from the client and only a CHAR function version was found by the server, the returned error fits. Changing the function definition or CASTing to a matching type can solve this kind of problem. (Note that a CHAR(1) parm could only correctly handle a single-character input if a value is CAST.)