There is an error on PostgreSQL that it gives on one of my select statements. I searched the web for an answer and came out empty handed. The answer given in another question did not suit my problem.
ERROR: failed to find conversion function from unknown to text
********** Error **********
ERROR: failed to find conversion function from unknown to text
SQL state: XX000
My query looks something like this:
Select *
from (select 'string' as Rowname, Data
From table)
Union all
(select 'string2' as Rowname, Data
From table)
The point of doing this is to specify what the row is at one point. The string being the name of the row. Here is my desired output:
Rowname Data
string 53
string2 87
Any possible way to fix this error?
Update: Type resolution in later versions of Postgres became smarter and this rule for UNION, CASE, and Related Constructs resolves it to text without explicit cast:
If all inputs are of type unknown, resolve as type text (the preferred type of the string category). [...]
SELECT 'string' AS rowname, data FROM tbl1
UNION ALL
SELECT 'string2', data FROM tbl2;
In older versions before Postgres 9.4 (?), or for non-default types you may still need to add an explicit cast like below.
Your statement has a couple of problems. But the error message implies that you need an explicit cast to declare the (yet unknown) data type of the string literal 'string':
SELECT text 'string' AS rowname, data FROM tbl1
UNION ALL
SELECT 'string2', data FROM tbl2;
It's enough to cast in one SELECT of a UNION query. Typically the first one, where column names are also decided. Subsequent SELECT lists with unknown types will fall in line.
In other contexts (like the VALUES clause attached to an INSERT) Postgres derives data types from target columns and tries to coerce to the right type automatically.
Select * from (select CAST('string' AS text) as Rowname, Data
From table) Union all
(select CAST('string2' AS text) as Rowname, Data
From table)
Reference
Related
I want to use array_position function in PostgreSQL (which takes array of some type and expression or value of the same type) for constructing query that returns rows in some arbitrary order (additional context: I want to enhance Ruby on Rails in_order_of feature which is currently implemented via unreadable CASE statement):
SELECT id, title, type
FROM posts
ORDER BY
array_position(ARRAY['SuperSpecial','Special','Ordinary']::varchar[], type),
published_at DESC;
The problem here is that requirement to do explicit type casting from type inferred by PostgreSQL from array literal (ARRAY['doh'] is text[]) to type of expression (type is varchar here). While varchar and text are coercible to each other, PostgreSQL requires explicit type cast, otherwise if omit it (like in array_position(ARRAY['doh'], type)) PostgreSQL will throw error (see this answer for details):
ERROR: function array_position(text[], character varying) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
While it is not a problem to specify explicit type cast in some static queries, it is problem in autogenerated queries when type of expression is unknown beforehand: array_position(ARRAY[1,2,3], id * 2) (what type has id * 2?)
I thought that pg_typeof() could help me, but it seems that it can't be used neither in :: operator nor in CAST operator (I've seen information that both forms aren't function forms, but syntax constructs, see this question for details):
SELECT id, title, type
FROM posts
ORDER BY array_position(CAST(ARRAY['SpecialPost','Post','Whatever'] AS pg_typeof(type)), type), id;
ERROR: type "pg_typeof" does not exist
LINE 1: ...on(CAST(ARRAY['SpecialPost','Post','Whatever'] AS pg_typeof(...
Question:
How to do dynamic typecast to expression type (say, to type of "posts"."id" * 2) in the same SQL query?
I would prefer to avoid extra roundtrip to database server (like executing SELECT pg_typeof("id" * 2) FROM "posts" LIMIT 1 and then using its result in generating of a new query) or writing some custom functions. Is it possible?
Better query
I want to enhance Ruby on Rails in_order_of feature which is currently implemented via unreadable CASE statement:
For starters, neither the awkward CASE construct nor array_position() are ideal solutions.
SELECT id, title, type
FROM posts
ORDER BY
array_position(ARRAY['SuperSpecial','Special','Ordinary']::varchar[], type),
published_at DESC;
There is a superior solution in Postgres:
SELECT id, title, type
FROM posts
LEFT JOIN unnest(ARRAY['SuperSpecial','Special','Ordinary']::varchar[]) WITH ORDINALITY o(type, ord) USING (type)
ORDER BY o.ord, published_at DESC;
This avoids calling the function array_position() for every row and is cheaper.
Equivalent short syntax with array literal and implicit column name:
SELECT id, title, type
FROM posts
LEFT JOIN unnest('{SuperSpecial,Special,Ordinary}'::varchar[]) WITH ORDINALITY type USING (type)
ORDER BY ordinality, published_at DESC;
db<>fiddle here
Added "benefit": it works with type-mismatch in Postgres 13 - as long as array type and column type are compatible.
The only possible caveat I can think of: If the passed array has duplicate elements, joined rows are duplicated accordingly. That wouldn't happen with array_position(). But duplicates would be nonsense for the expressed purpose in any case. Make sure to pass unique array elements.
See:
ORDER BY the IN value list
PostgreSQL unnest() with element number
Improved functionality in Postgres 14
The error you report is going away with Postgres 14:
ERROR: function array_position(text[], character varying) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Quoting the release notes:
Allow some array functions to operate on a mix of compatible data
types (Tom Lane)
The functions array_append(), array_prepend(), array_cat(),
array_position(), array_positions(), array_remove(),
array_replace(), and width_bucket() now take anycompatiblearray
instead of anyarray arguments. This makes them less fussy about
exact matches of argument types.
And the manual on anycompatiblearray:
Indicates that a function accepts any array data type, with automatic promotion of multiple arguments to a common data type
So, while this raises the above error msg in Postgres 13:
SELECT array_position(ARRAY['a','b','c']::text[], 'd'::varchar);
.. the same just works in Postgres 14.
(Your query and error msg show flipped positions for text and varchar, but all the same.)
To be clear, calls with compatible types now just work, incompatible types still raise an exception:
SELECT array_position('{1,2,3}'::text[], 3);
(The numeric literal 3 defaults to type integer, which is incompatible with text.)
Answer to actual question
.. which may be irrelevant by now. But as proof of concept:
CREATE OR REPLACE FUNCTION posts_order_by(_order anyarray)
RETURNS SETOF posts
LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY EXECUTE format (
$$
SELECT p.*
FROM posts p
LEFT JOIN unnest($1) WITH ORDINALITY o(type, ord) ON (o.type::%s = p.type)
ORDER BY o.ord, published_at DESC
$$
, (SELECT atttypid::regtype
FROM pg_attribute
WHERE attrelid = 'posts'::regclass
AND attname = 'type')
)
USING _order;
END
$func$;
db<>fiddle here
Doesn't make a whole lot of sense, as the type of posts.id should be well-known at the time of writing the function, but there may be special cases ...
Now both of these calls work:
SELECT * FROM posts_order_by('{SuperSpecial,Special,Ordinary}'::varchar[]);
SELECT * FROM posts_order_by('{1,2,3}'::int[]);
Though the second typically doesn't make sense.
Related, with links to more:
Executing queries dynamically in PL/pgSQL
Follow up to this question.
Say that on postgres, I have a table TABLE1 containing the columns id (integer), name (string):
create table table1 (id int primary key,name varchar(100));
insert into table1(id,name) values(5,'a');
insert into table1(id,name) values(6,'b');
insert into table1(id,name) values(7,'c');
insert into table1(id,name) values(55,'a');
And attempt to run the following queries:
with base (x) as (select 5 as x from table1)
select table1.name from base, table1 where table1.id = base.x;
with base (x) as (select 'a' as x from table1)
select table1.name from base, table1 where table1.name = base.x;
On sqlfiddle, the former yields a result, whilst the latter fails with the message:
ERROR: failed to find conversion function from unknown to text
On postgres 13.3 which I have installed locally, however, neither errs. (Nor similar queries on oracle and sqlite.)
My first question is, does this error stem from an issue within sqlfiddle, or has it persisted within earlier versions of postgres?
And second, does this count as a bug? Generally, are constant columns (or values) in SQL assumed to be typeless, and any operations on them are undefined unless there happens to be an implicit / explicit cast in place?
Per my understanding, using constant columns for joining is generally inadvisable as it thwarts indexing, but it seems a little odd in any programming language to have difficulties telling one constant format apart from another.
The cause is that a string literal in PostgreSQL is of type unknown, not text, because all data types have a string representation. Normally, the actual type is determined by context.
A number literal, however, has data type integer, bigint or numeric, based on its size and the presence of a fractional part:
SELECT pg_typeof('a');
pg_typeof
═══════════
unknown
(1 row)
SELECT pg_typeof(5);
pg_typeof
═══════════
integer
(1 row)
Now the subquery select 'a' as x from table1 has no context to determine a better type than unknown for the result column, which makes the comparison in the join condition fail.
Since this is strange and undesirable behavior, PostgreSQL v10 has demoted unknown from being a regular data type (you could create columns of that type!) to a “pseudo-type”. It also coerced unknown to text in SELECT lists, which is why you cannot reproduce that on v10 or later.
This only happens when I Union a Select statement from a View (which works fine on its own), with a Select statement which is hard-coded to return a specific row.
Select * From View
UNION ALL
Select 'text' as Col1, 'text1' as Col2
This is just to give you an idea of what I am doing.
Both statements work just fine when run independently.
Thank you!
You need to explicitly convert the types in the first part of the union:
select cast(col1 as varchar(255)) as col1, cast(col2 as varchar(255) as col2
from view
union all
select 'text', 'tex1';
As sort-of explained in the documentation:
Is a query specification or query expression that returns data to be
combined with the data from another query specification or query
expression. The definitions of the columns that are part of a UNION
operation do not have to be the same, but they must be compatible
through implicit conversion. When data types differ, the resulting
data type is determined based on the rules for data type precedence.
When the types are the same but differ in precision, scale, or length,
the result is determined based on the same rules for combining
expressions. For more information, see Precision, Scale, and Length
(Transact-SQL).
I'm the first to admit that this isn't 100% clear. But, the type precedence rules mean that SQL Server prefers numeric types over character types and hence you can get conversion problems.
The issue was that in the view I had several non-numeric values in one numeric column. I wasn't explicitly setting the data type for this column and SQL was handling it on its own so I wasn't aware of the situation.
It was only becoming an issue when the second part of the union returned a numeric value in the same column.
I had to review the data line by line to realize where the problem was.
I tried to search for previous articles related to this, but I can't find one specific to my situation. And because I'm brand new to StackOverflow, I can't post pictures so I'll try to describe it.
I have two datasets. One is 34 rows, 1 column of all NULLs. The other 13 rows, 1 column of varchars.
When I try to UNION ALL these two together, i get the following error:
Conversion failed when converting the varchar value to data type int.
I don't understand why I'm getting this error. I've UNIONed many NULL columns and varchar columns before, among many other types and I don't get this conversion error.
Can anyone offer suggestions why this error occurs?
The error occurs because you have corresponding columns in the two of the subqueries where the type of one is an integer and the type of the other is a character. Then, the character value has -- in at least one row -- a value that cannot be automatically converted to an integer.
This is easy to replicate:
select t.*
from (select 'A' as col union all
select 1
) t;
Here is the corresponding SQL Fiddle.
SQL Server uses pretty sophisticated type precedence rules for determining the destination type in a union. In practice, though, it is best to avoid using implicit type conversions. Instead, explicitly cast the columns to the type you intend.
EDIT:
The situation with NULL values is complicated. By itself, the NULL value has no type. So, the following works fine:
select NULL as col
union all
select 'A';
If you type the NULL, then the query will fail:
select cast(NULL as int) as col
union all
select 'A';
Also, if you put SQL Server in a position where it has to assign a type, then SQL Server will make the NULL an integer. Every column in a table or result set needs a type, so this will also fail:
select (select NULL) as col
union all
select 'A';
Perhaps your queries are doing something like this.
I have also encountered this error when I accidentally had the fields out of sequence in the 2 SELECT queries that I was unioning. Adjusting the fields' sequence fixed the problem.
A very easy one for someone,
The following insert is giving me the
ORA-01722: invalid number
why?
INSERT INTO CUSTOMER VALUES (1,'MALADY','Claire','27 Smith St Caulfield','0419 853 694');
INSERT INTO CUSTOMER VALUES (2,'GIBSON','Jake','27 Smith St Caulfield','0415 713 598');
INSERT INTO CUSTOMER VALUES (3,'LUU','Barry','5 Jones St Malvern','0413 591 341');
INSERT INTO CUSTOMER VALUES (4,'JONES','Michael','7 Smith St Caulfield','0419 853 694');
INSERT INTO CUSTOMER VALUES (5,'MALADY','Betty','27 Smith St Knox','0418 418 347');
An ORA-01722 error occurs when an attempt is made to convert a character string into a number, and the string cannot be converted into a number.
Without seeing your table definition, it looks like you're trying to convert the numeric sequence at the end of your values list to a number, and the spaces that delimit it are throwing this error. But based on the information you've given us, it could be happening on any field (other than the first one).
Suppose tel_number is defined as NUMBER - then the blank spaces in this provided value cannot be converted into a number:
create table telephone_number (tel_number number);
insert into telephone_number values ('0419 853 694');
The above gives you a
ORA-01722: invalid number
Here's one way to solve it. Remove non-numeric characters then cast it as a number.
cast(regexp_replace('0419 853 694', '[^0-9]+', '') as number)
Well it also can be :
SELECT t.col1, t.col2, ('test' + t.col3) as test_col3
FROM table t;
where for concatenation in oracle is used the operator || not +.
In this case you get : ORA-01722: invalid number ...
This is because:
You executed an SQL statement that tried to convert a string to a
number, but it was unsuccessful.
As explained in:
Oracle/PLSQL: ORA-01722 Error.
To resolve this error:
Only numeric fields or character fields that contain numeric values
can be used in arithmetic operations. Make sure that all expressions
evaluate to numbers.
As this error comes when you are trying to insert non-numeric value into a numeric column in db it seems that your last field might be numeric and you are trying to send it as a string in database. check your last value.
Oracle does automatic String2number conversion, for String column values! However, for the textual comparisons in SQL, the input must be delimited as a String explicitly: The opposite conversion number2String is not performed automatically, not on the SQL-query level.
I had this query:
select max(acc_num) from ACCOUNTS where acc_num between 1001000 and 1001999;
That one presented a problem: Error: ORA-01722: invalid number
I have just surrounded the "numerical" values, to make them 'Strings', just making them explicitly delimited:
select max(acc_num) from ACCOUNTS where acc_num between '1001000' and '1001999';
...and voilà: It returns the expected result.
edit:
And indeed: the col acc_num in my table is defined as String. Although not numerical, the invalid number was reported. And the explicit delimiting of the string-numbers resolved the problem.
On the other hand, Oracle can treat Strings as numbers. So the numerical operations/functions can be applied on the Strings, and these queries work:
select max(string_column) from TABLE;
select string_column from TABLE where string_column between '2' and 'z';
select string_column from TABLE where string_column > '1';
select string_column from TABLE where string_column <= 'b';
In my case the conversion error was in functional based index, that I had created for the table.
The data being inserted was OK. It took me a while to figure out that the actual error came from the buggy index.
Would be nice, if Oracle could have gave more precise error message in this case.
If you do an insert into...select * from...statement, it's easy to get the 'Invalid Number' error as well.
Let's say you have a table called FUND_ACCOUNT that has two columns:
AID_YEAR char(4)
OFFICE_ID char(5)
And let's say that you want to modify the OFFICE_ID to be numeric, but that there are existing rows in the table, and even worse, some of those rows have an OFFICE_ID value of ' ' (blank). In Oracle, you can't modify the datatype of a column if the table has data, and it requires a little trickery to convert a ' ' to a 0. So here's how to do it:
Create a duplicate table: CREATE TABLE FUND_ACCOUNT2 AS SELECT * FROM FUND_ACCOUNT;
Delete all the rows from the original table: DELETE FROM FUND_ACCOUNT;
Once there's no data in the original table, alter the data type of its OFFICE_ID column: ALTER TABLE FUND_ACCOUNT MODIFY (OFFICE_ID number);
But then here's the tricky part. Because some rows contain blank OFFICE_ID values, if you do a simple INSERT INTO FUND_ACCOUNT SELECT * FROM FUND_ACCOUNT2, you'll get the "ORA-01722 Invalid Number" error. In order to convert the ' ' (blank) OFFICE_IDs into 0's, your insert statement will have to look like this:
INSERT INTO FUND_ACCOUNT (AID_YEAR, OFFICE_ID) SELECT AID_YEAR, decode(OFFICE_ID,' ',0,OFFICE_ID) FROM FUND_ACCOUNT2;
I have found that the order of your SQL statement parameters is also important and the order they are instantiated in your code, this worked in my case when using "Oracle Data Provider for .NET, Managed Driver".
var sql = "INSERT INTO table (param1, param2) VALUES (:param1, :param2)";
...
cmd.Parameters.Add(new OracleParameter("param2", Convert.ToInt32("100")));
cmd.Parameters.Add(new OracleParameter("param1", "alpha")); // This should be instantiated above param1.
Param1 was alpha and param2 was numeric, hence the "ORA-01722: invalid number" error message. Although the names clearly shows which parameter it is in the instantiation, the order is important. Make sure you instantiate in the order the SQL is defined.
For me this error was a bit complicated issue.
I was passing a collection of numbers (type t_numbers is table of number index by pls_integer;) to a stored procedure. In the stored proc there was a bug where numbers in this collection were compared to a varchar column
select ... where ... (exists (select null from table (i_coll) ic where ic.column_value = varchar_column))
Oracle should see that ic.column_value is integer so shouldn't be compared directly to varchar but it didn't (or there is trust for conversion routines).
Further complication is that the stored proc has debugging output, but this error came up before sp was executed (no debug output at all).
Furthermore, collections [<empty>] and [0] didn't give the error, but for example [1] errored out.
The ORA-01722 error is pretty straightforward. According to Tom Kyte:
We've attempted to either explicity or implicity convert a character string to a number and it is failing.
However, where the problem is is often not apparent at first. This page helped me to troubleshoot, find, and fix my problem. Hint: look for places where you are explicitly or implicitly converting a string to a number. (I had NVL(number_field, 'string') in my code.)
This happened to me too, but the problem was actually different: file encoding.
The file was correct, but the file encoding was wrong. It was generated by the export utility of SQL Server and I saved it as Unicode.
The file itself looked good in the text editor, but when I opened the *.bad file that the SQL*loader generated with the rejected lines, I saw it had bad characters between every original character. Then I though about the encoding.
I opened the original file with Notepad++ and converted it to ANSI, and everything loaded properly.
In my case it was an end of line problem, I fixed it with dos2unix command.
In my case I was trying to Execute below query, which caused the above error ( Note : cus_id is a NUMBER type column)
select *
from customer a
where a.cus_id IN ('115,116')
As a solution to the caused error, below code fragment(regex) can be used which is added in side IN clause (This is not memory consuming as well)
select *
from customer a
where a.cus_id IN (select regexp_substr (
com_value,
'[^,]+',
1,
level
) value
from (SELECT '115,116' com_value
FROM dual)rws
connect by level <=
length ( com_value ) - length ( replace ( com_value, ',' ) ) + 1)
try this as well, when you have a invalid number error
In this
a.emplid is number and b.emplid is an varchar2 so if you got to convert one of the sides
where to_char(a.emplid)=b.emplid
You can always use TO_NUMBER() function in order to remove this error.This can be included as INSERT INTO employees phone_number values(TO_NUMBER('0419 853 694');