SQL Code = -420 Invalid character found in a character string argument of the function "decfloat" - sql

I am having trouble with this code.
(SELECT r.SITE_ID, count(distinct r.NIIN)
FROM
(SELECT t.SITE_ID, t.NIIN, B.DT_INVT, B.DT_CRTD,CAST(
case when
B.DT_INVT = '0000000' then B.DT_CRTD + 2000
when B.DT_INVT IS NULL then B.DT_CRTD + 2000
when B.DT_INVT = ' ' then B.DT_CRTD + 2000
ELSE B.DT_INVT + 2000
End as INT) As DueDate
FROM
(SELECT A.SITE_ID, A.NIIN
FROM DDCNENVR.QBO A
WHERE NOT (A.RIC IN ('SMS', 'S9W', 'S9D'))
and A.SITE_ID in ('HECL', 'HECN')
GROUP BY A.SITE_ID, A.NIIN) as t
inner join DDCNENVR.QBS B on t.NIIN = B.NIIN and t.SITE_ID = B.SITE_ID) as r
where r.DueDate between 2018206 and 2019273
GROUP BY r.SITE_ID)
The same code works for some dbs but fails in others.
After exporting the data without using the duedate between statement, the column types according to excel are as follows:
B.Dt_inv and B.dt_created are text
Duedate exports as number

In Db2 V11.1.0.0 and above you could use a function such as this to check if a value can be CAST to a DECIMAL.
CREATE OR REPLACE FUNCTION IS_DECIMAL(s VARCHAR(255))
RETURNS SMALLINT
LANGUAGE SQL
CONTAINS SQL
DETERMINISTIC
NO EXTERNAL ACTION
RETURN
REGEXP_LIKE(s, '^\s*[+-]?\s*((\d+\.?\d*)|(\d*\.?\d+))\s*$')
Use it like this
SELECT DT_INVT FROM DDCNENVR.QBS WHERE IS_DECIMAL(DT_INVT) = 0
It is not perfect as it does not allow all formats (e.g. 1e3 is castable to DECIMAL, but this function will say it is not), but it will catch e.g. 12 34 as not castable to DECIMAL whereas the TRANSLATE function would not.
It also does not check the length of the string to ensure that it is not more than 31 decimal digits.

Related

Selecting with INT value against STR field

I'm trying to select records from a table using SQL Developer based on an INT value (in one file) to a STR (in the other file) and I'm using a nested(?) query:
select *
from proddta.FQ584871
where tdrscn in (select rmrscn from proddta.f48310)
and tdan8 > 1 and tdeqhr > 0
and tddoco not in (select glsbl from proddta.f0911)
In this example the TDDOCO is an INT and the GLSBL is a STR. The match would be TDDOCO = 456123 to the GLSBL = 00456123.
Thank you for any assistance
I've tried to CAST and the STR and VARCHAR but they don't appear to work when I'm trying to convert the TDDOCO.
I've tried:
tddoco not in (select to_number(ltrim(glsbl,'0')) from proddta.f0911
and I've tried:
to_char(tddoco) not in (select glsbl from proddta.f0911)
and I get an invalid number error.

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.

where statement not allowed with group by function

I'm still a newbie with oracle, here I have a query that returns data like :
0.52
0.01
1
12
Desired result :
1
12
i have tried to do something like this in where part but it returns group function is not allowed here:
to_char((Max(start_time_timestamp+ (2/24))- p.port_statusmoddat), 999.999) >1
the query I'm working with:
select to_char((Max(start_time_timestamp+ (2/24))- p.port_statusmoddat), 999.999) as Diff
from ZAJBIREJ.UDR_ST r,directory_number d, CONTR_SERVICES_CAP C, MPUSNTAB SN, unicam.vw_contr_imsi_sim x, port p
where reject_reason_code = 'ISUBS'
and r.s_p_port_address = p.port_num (+)
and c.co_id = x.co_id (+)
and s_p_number_address = d.dn_num (+)
and d.dn_id =c.dn_id
AND C.SNCODE = sn.SNCODE
and C.MAIN_DIRNUM = 'X'
and c.cs_deactiv_date is null
and p.port_status = 'd'
AND nvl(C.cs_deactiv_date,'01-jan-2300') = (SELECT MAX(nvl(CA.cs_deactiv_date,'01-jan-2300'))
FROM CONTR_SERVICES_CAP CA, MPUSNTAB SNT
WHERE CA.DN_ID = D.DN_ID
AND SNT.SHDES = SN.SHDES)
group by reject_reason_code ,c.co_id, s_p_number_address,r.s_p_port_address,x.IMSI,p.port_status, p.port_statusmoddat
You need to use the HAVING clause:
group by reject_reason_code ,c.co_id, s_p_number_address, r.s_p_port_address,
x.IMSI, p.port_status, p.port_statusmoddat
having Max(start_time_timestamp+ (2/24))- p.port_statusmoddat >1
I also removed the redundant TO_CHAR as you want to test the number exceeds 1, not that a string of characters exceeds 1.

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.)

How do I convert a number to a numeric, comma-separated formatted string?

Is there an easy way to convert a number (in my case an integer) to a comma separated nvarchar string?
For instance, if I had an int value of 1000000 stored in a field, how can I convert it to an nvarchar string with the outputted result of "1,000,000"?
I could easily write a function to do this but I wanted to be sure there wasn't an easier way involving a call to either CAST or CONVERT.
The reason you aren't finding easy examples for how to do this in T-SQL is that it is generally considered bad practice to implement formatting logic in SQL code. RDBMS's simply are not designed for presentation. While it is possible to do some limited formatting, it is almost always better to let the application or user interface handle formatting of this type.
But if you must (and sometimes we must!) use T-SQL, cast your int to money and convert it to varchar, like this:
select convert(varchar,cast(1234567 as money),1)
If you don't want the trailing decimals, do this:
select replace(convert(varchar,cast(1234567 as money),1), '.00','')
Good luck!
For SQL Server 2012, or later, an easier solution is to use FORMAT ()Documentation.
EG:
SELECT Format(1234567.8, '##,##0')
Results in: 1,234,568
Quick & dirty for int to nnn,nnn...
declare #i int = 123456789
select replace(convert(varchar(128), cast(#i as money), 1), '.00', '')
>> 123,456,789
Not sure it works in tsql, but some platforms have to_char():
test=#select to_char(131213211653.78, '9,999,999,999,999.99');
to_char
-----------------------
131,213,211,653.78
test=# select to_char(131213211653.78, '9G999G999G999G999D99');
to_char
-----------------------
131,213,211,653.78
test=# select to_char(485, 'RN');
to_char
-----------------
CDLXXXV
As the example suggests, the format's length needs to match that of the number for best results, so you might want to wrap it in a function (e.g. number_format()) if needed.
Converting to money works too, as point out by the other repliers.
test=# select substring(cast(cast(131213211653.78 as money) as varchar) from 2);
substring
--------------------
131,213,211,653.78
Although formatting belongs to the Presentation layer, SQL Server 2012 and above versions provide FORMAT() function which provides one of the quickest and easiest way to format output. Here are some tips & examples:
Syntax: Format( value, format [, culture ] )
Returns: Format function returns NVarchar string formatted with the specified format and with optional culture. (Returns NULL for invalid format-string.)
Note: The Format() function is consistent across CLR / all .NET languages and provides maximum flexibility to generate formatted output.
Following are few format types that can be achieved using this function:
Numeric/Currency formatting - 'C' for currency, 'N' number without currency symbol, 'x' for Hexa-decimals.
Date/Time formatting - 'd' short date, 'D' long date, 'f' short full date/time, 'F' long full date/time, 't' short time, 'T' long time, 'm' month+day, 'y' year+month.
Custom formatting - you can form your own-custom format using certain symbols/characters, such as dd, mm, yyyy etc. (for Dates). hash (#) currency symbols (£ $ etc.), comma(,) and so on. See examples below.
Examples:
Examples of Built-in Numeric/Currency Formats:
 select FORMAT(1500350.75, 'c', 'en-gb') --> £1,500,350.75
 select FORMAT(1500350.75, 'c', 'en-au') --> $1,500,350.75
 select FORMAT(1500350.75, 'c', 'en-in') --> ₹ 15,00,350.75
Examples of Built-in Date Formats:
 select FORMAT(getdate(), 'd', 'en-gb') --> 20/06/2017
 select FORMAT(getdate(), 'D', 'fr-fr') --> mardi 20 juin 2017
 select FORMAT(getdate(), 'F', 'en-us') --> Tuesday, June 20, 2017 10:41:39 PM
 select FORMAT(getdate(), 'T', 'en-gb') --> 22:42:29
Examples of Custom Formatting:
 select FORMAT(GETDATE(), 'ddd dd/MM/yyyy') --> Tue 20/06/2017
 select FORMAT(GETDATE(), 'dddd dd-MMM-yyyy') --> Tuesday 20-Jun-2017
 select FORMAT(GETDATE(), 'dd.MMMM.yyyy HH:mm:ss') --> 20.June.2017 22:47:20
 select FORMAT(123456789.75,'$#,#.00') --> $123,456,789.75
 select FORMAT(123456789.75,'£#,#.0') --> £123,456,789.8
See MSDN for more information on FORMAT() function.
For SQL Server 2008 or below convert the output to MONEY first then to VARCHAR (passing "1" for the 3rd argument of CONVERT() function to specify the "style" of output-format), e.g.:
 select CONVERT(VARCHAR, CONVERT(MONEY, 123456789.75), 1) --> 123,456,789.75
You really shouldn't be doing that in SQL - you should be formatting it in the middleware instead. But I recognize that sometimes there is an edge case that requires one to do such a thing.
This looks like it might have your answer:
How do I format a number with commas in T-SQL?
I looked at several of the options. Here are my two favorites, because I needed to round the value.
,DataSizeKB = replace(convert(varchar,Cast(Round(SUM(BigNbr / 0.128),0)as money),1), '.00','')
,DataSizeKB2 = format(Round(SUM(BigNbr / 0.128),0),'##,##0')
-----------------
--- below if the full script where I left DataSizeKB in both methods -----------
--- enjoy ---------
--- Hank Freeman : hfreeman#msn.com
-----------------------------------
--- Scritp to get rowcounts and Memory size of index and Primary Keys
SELECT
FileGroupName = DS.name
,FileGroupType =
CASE DS.[type]
WHEN 'FG' THEN 'Filegroup'
WHEN 'FD' THEN 'Filestream'
WHEN 'FX' THEN 'Memory-optimized'
WHEN 'PS' THEN 'Partition Scheme'
ELSE 'Unknown'
END
,SchemaName = SCH.name
,TableName = OBJ.name
,IndexType =
CASE IDX.[type]
WHEN 0 THEN 'Heap'
WHEN 1 THEN 'Clustered'
WHEN 2 THEN 'Nonclustered'
WHEN 3 THEN 'XML'
WHEN 4 THEN 'Spatial'
WHEN 5 THEN 'Clustered columnstore'
WHEN 6 THEN 'Nonclustered columnstore'
WHEN 7 THEN 'Nonclustered hash'
END
,IndexName = IDX.name
,RowCounts = replace(convert(varchar,Cast(p.rows as money),1), '.00','') --- MUST show for all types when no Primary key
--,( Case WHEN IDX.[type] IN (2,6,7) then 0 else p.rows end )as Rowcounts_T
,AllocationDesc = AU.type_desc
/*
,RowCounts = p.rows --- MUST show for all types when no Primary key
,TotalSizeKB2 = Cast(Round(SUM(AU.total_pages / 0.128),0)as int) -- 128 pages per megabyte
,UsedSizeKB = Cast(Round(SUM(AU.used_pages / 0.128),0)as int)
,DataSizeKB = Cast(Round(SUM(AU.data_pages / 0.128),0)as int)
--replace(convert(varchar,cast(1234567 as money),1), '.00','')
*/
,TotalSizeKB = replace(convert(varchar,Cast(Round(SUM(AU.total_pages / 0.128),0)as money),1), '.00','') -- 128 pages per megabyte
,UsedSizeKB = replace(convert(varchar,Cast(Round(SUM(AU.used_pages / 0.128),0)as money),1), '.00','')
,DataSizeKB = replace(convert(varchar,Cast(Round(SUM(AU.data_pages / 0.128),0)as money),1), '.00','')
,DataSizeKB2 = format(Round(SUM(AU.data_pages / 0.128),0),'##,##0')
,DataSizeKB3 = format(SUM(AU.data_pages / 0.128),'##,##0')
--SELECT Format(1234567.8, '##,##0.00')
---
,is_default = CONVERT(INT,DS.is_default)
,is_read_only = CONVERT(INT,DS.is_read_only)
FROM
sys.filegroups DS -- you could also use sys.data_spaces
LEFT JOIN sys.allocation_units AU ON DS.data_space_id = AU.data_space_id
LEFT JOIN sys.partitions PA
ON (AU.[type] IN (1,3) AND
AU.container_id = PA.hobt_id) OR
(AU.[type] = 2 AND
AU.container_id = PA.[partition_id])
LEFT JOIN sys.objects OBJ ON PA.[object_id] = OBJ.[object_id]
LEFT JOIN sys.schemas SCH ON OBJ.[schema_id] = SCH.[schema_id]
LEFT JOIN sys.indexes IDX
ON PA.[object_id] = IDX.[object_id] AND
PA.index_id = IDX.index_id
-----
INNER JOIN
sys.partitions p ON obj.object_id = p.OBJECT_ID AND IDX.index_id = p.index_id
WHERE
OBJ.type_desc = 'USER_TABLE' -- only include user tables
OR
DS.[type] = 'FD' -- or the filestream filegroup
GROUP BY
DS.name ,SCH.name ,OBJ.name ,IDX.[type] ,IDX.name ,DS.[type] ,DS.is_default ,DS.is_read_only -- discard different allocation units
,p.rows ,AU.type_desc ---
ORDER BY
DS.name ,SCH.name ,OBJ.name ,IDX.name
---
;
remove the commas with a replace and convert:
CONVERT(INT,REPLACE([varName],',',''))
where varName is the name of the variable that has numeric values in it with commas