Treat TO_NUMBER() invalid format errors as NULL - sql

I have a string column which usually contains integers in two formats... zero-padded, and not:
5
05
I want to sort based on these values numerically. To do that I do something like:
SELECT * FROM things ORDER BY TO_NUMBER(num, '0000');
This works fine, but sometimes there is invalid data, like abc, or !## in this column. Postgres becomes unhappy with me:
ERROR: invalid input syntax for type numeric: " "
What I'd like to do is treat invalid values/failures of TO_NUMBER() as NULL so that they are sorted accordingly. Is this possible? Or, some other alternative?

If you are using PostgreSQL, you can use this query:
SELECT * FROM things ORDER BY
TO_NUMBER((case when num ~ '^[0-9\.]+$' THEN num else '0' end),'0000');

Related

SQL Decode format numbers only

I want to format amounts to salary format, e.g. 10000 becomes 10,000, so I use to_char(amount, '99,999,99')
SELECT SUM(DECODE(e.element_name,'Basic Salary',to_char(v.screen_entry_value,'99,999,99'),0)) Salary,
SUM(DECODE(e.element_name,'Transportation Allowance',to_char(v.screen_entry_value,'99,999,99'),0)) Transportation,
SUM(DECODE(e.element_name,'GOSI Processing',to_char(v.screen_entry_value,'99,999,99'),0)) GOSI,
SUM(DECODE(e.element_name,'Housing Allowance',to_char(v.screen_entry_value,'99,999,99'),0)) Housing
FROM values v,
values_types vt,
elements e
WHERE vt.value_type = 'Amount'
this gives error invalid number because not all values are numbers until value_type is equal to Amount but I guess decode check all values anyway although what I know is that the execution begins with from then where then select, what's going wrong here?
You said you added decode(...), but it looks like you might have actually added sum(decode(...)).
You are converting your values to strings with to_char(v.screen_entry_value,'99,999,99'), so your decode() generates a string - the default 0 will be converted to '0' - giving you a value like '1,234,56'. Then you are aggregating those, so sum() has to implicitly convert those strings to numbers - and it is throwing the error when it tries to do that:
select to_number('1,234,56') from dual
will also get "ORA-01722: invalid number", unless you supply a similar format mask so it knows how to interpret it. You could do that, e.g.:
SUM(to_number(DECODE(e.element_name,'Basic Salary',to_char(v.screen_entry_value,'99,999,99'),0),'99,999,99'))
... but it's maybe more obvious that something is strange, and even if you did, you would end up with a number, not a formatted string.
So instead of doing:
SUM(DECODE(e.element_name,'Basic Salary',to_char(v.screen_entry_value,'99,999,99'),0))
you should format the result after aggregating:
to_char(SUM(DECODE(e.element_name,'Basic Salary',v.screen_entry_value,0)),'99,999,99')
fiddle with dummy tables, data and joins.

Can't compare a values in access

Here is the code, the field Автомобили.Описание is instance of Short Text in a result table of a Автомобили query
SELECT Автомобили.НомVIN, Автомобили.ФИО, Автомобили.РегНомер, Автомобили.Описание
FROM Автомобили
WHERE (((Year(Now()) - CInt([Автомобили].[Описание]) = 40)))
ORDER BY Автомобили.ФИО, Автомобили.Описание;
The thing is that if I want to just compare values in WHERE clause only with '=' it seems fine, everything works properly. But when I try to compare them by '<' or '>' or '<=' or '>=" the Access throws an error "Datatype mismatch in criteria expression". What is wring with it?
Year() returns an Integer, so your criteria examples are correct and perfectly valid. So, it is something else.
Try to leave out the ordering or sort on the numeric value:
SELECT
Автомобили.НомVIN,
Автомобили.ФИО,
Автомобили.РегНомер,
Автомобили.Описание
FROM
Автомобили
WHERE
Year(Date()) - CInt([Автомобили].[Описание]) = 40
ORDER BY
Автомобили.ФИО,
CInt(Автомобили.Описание);

Postgresql ERROR: operator does not exist: date ~~ unknown

When I do this query, I have no problems:
SELECT a.value, b.label AS campo, 'date' AS tipo
FROM contenido.field_value_textarea a
JOIN estructura.field b ON a.field=b.id
WHERE a.value LIKE '%aaa%'
contenido.field_value_textarea is character varying(2000)
But if I try to select from:
contenido.field_value_fecha which type is date I got this error message:
ERROR: operator does not exist: date ~~ unknown
What I'm trying to do is searching between different tables, each query select FROM it's table. Some tables use text values, textarea values, integer values, and it works, but when the value is date all fails. What can I do?
EDIT: By the way, my date values are like this: 2009-05-01
The ~~ operator is actually the LIKE operator.
You are trying to use an expression that looks like:
contenido.field_value_fecha.value LIKE '%aaaa%'
That is, you're trying to compare a date with a string (which, without the adequate context, is considered to be of type 'unknown'), and decide if the date looks like something.
If you actually want to do such a comparison, you need to convert the date to a string, which can be done by means of:
contenido.field_value_fecha.value::text LIKE '%aaaa%'
or (using standard SQL):
CAST(contenido.field_value_fecha.value AS text) LIKE '%aaaa%'
This will be syntactically correct... Whether it is meaningful or not, is a different part of the story.

Convert varchar dates (BC & AD) to date format in sql

Dates are stored like this in another table as varchars
select wkdocre from works;
wkdocre
-------------
+1654/12/31
+1706/12/31
+1667/12/31
-0332/12/31
-0332/12/31
-1295/12/31
And I want to insert these dates into another table with an attribute that is of type date like this
update ns_works set wor_workcreationdate=(select wkdocre from works where wor_workcreationdate=wkdocre);
I get this error
ERROR: operator does not exist: ns_workcreationdate = dateofcreation
LINE 1: ...lect wkdocre from works where wor_workcreationdate=wkdocre);
^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Thank-you
Desired results
select wor_creationdate from ns_works;
wor_creationdate
-------------
1654/12/31
1706/12/31
1667/12/31
-0332/12/31
-0332/12/31
-1295/12/31
You need explicit conversion; try something like that:
... SET wor_workcreationdate =
to_date(
(select wkdocre
from works
where wor_workcreationdate = to_date(wkdocre, 'YYYY/MM/DD')),
'YYYY/MM/DD'
)
Writing years BC with a minus sign is incorrect though; PostgreSQL will interpret -1295 as 1296 BC, since year 0 is actually 1 BC. You might want to fix your works table and use YYYY/MM/DD BC as format specifier.

PostgreSQL text array - query as integer, ignoring non-digits

I have a table of people. Each person can have several regnums (mostly integers but some like M/2344 and W345). To make things a bit more complicated, there are NULLs, empties, and strings like 'NA'. Due to their unpredictable composition, the regnums are stored in a text array field (e.g. {12345,M/2344} and {3459,NA}).
Because most people have regnums that can be treated as integers, I would like to be able to do things with this field like find people with a regnum between, say, 491555 and 491685.
I've tried:
SELECT id,forename,surname,regnum FROM (SELECT *, unnest(regnum) reg FROM people) as TBL WHERE reg BETWEEN '491555' AND '491685';
but results include out-of-range regnums, e.g. 49162. I assume this is because the unnested regnum field is still a text field(?)
I've also tried casting the regnum as an integer field - unnest(regnum::integer[]) - but I get errors:
Error in query: ERROR: invalid input syntax for integer: "NA"
I think I'm on the right track, but I don't get how to ignore non-int-like regnums. Any ideas?
You can test if a text value consists only of digits by checking it with regular expression, like this:
SELECT '1234' ~ '^[0-9]+$' -- true
SELECT 'NA' ~ '^[0-9]+$' -- false
So, in your case you need to cast value to integer only if it is numerical:
WHERE (CASE WHEN reg ~ '^[0-9]+$' THEN reg::integer ELSE null END) BETWEEN 491555 AND 491685