Unioned select statements cause an int overflow error - sql

I am trying to run this unioned select statement and I'm getting an int overflow error.
The first select has an ID which is an integer so I've cast it as a varchar(25).
This levels the playing field, or so I thought, because the ID values in the subsequent two selects with a maximum size of varchar(25).
This is the error.
The conversion of the varchar value '24546133202216601' overflowed an int column
This might be a duplicate, but I couldn't find an identical question, so is there a way around this?
SELECT CAST(ID AS varchar(25)) AS thisID FROM tblA
UNION
SELECT ID AS thisID FROM tblB
UNION
SELECT ID AS thisID FROM tblC

From documentation
The data types must be compatible.
The definitions of the columns that are part of a UNION operation
don't 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.

Related

Selecting and comparing columns which contain constants

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.

The data types in each column don't need to be compatible between the UNION queries

I read here that to be able to use SQL UNION queries,
data types in each column must be compatible between the individual queries.
So select a, b from table1 UNION select c, d from table2, for this query to work, we need a and c data types to be compatible.
However, when I try to test that, and make table users having two columns (id int, name varchar(15)), and table calc having two values (x int, y int), and after inserting elements
(1, 'saad') into table users, and values (3, 5) into table calc, and try query select * from users union select * from calc;, it shows the results as follows without any errors:
1 | saad
3 | 5
although name and y data types is not compatible, and was supposed to cause error
Conversion failed when converting the int value 5 to data type varchar
I thought it may be browser specific behavior, so I tried this also in google chrome, but it worked without any errors also!
Can someone explain to me why?
Thanks in advance.
Edit:
I'm using MySql 5.6
With MS SQL, there's a distinction between UNION and UNION ALL.
In the case of a UNION query, each value is compared to every other value for that column across all of select clauses. This might result in fewer records in final result than exist in the original select clause results. Even if you didn't intend for it, the optimizer will compare values from a and c along with b and d to find the uinion of those two sets. That also means that the datatype if they're different goes through an implicit data conversion to sql_variant to accomplish the goal of the union request.
Since UNION ALL is just stacking the sets one on top of each other, there's less of a need to compare the values.

How to do explicit conversion of FLOAT to a VARCHAR field in SQL

I'm getting a query from a column float (with no precision) and inserting it in another table and comumn float (with no precision as well) but I'm getting this error:
Error (265) Insufficient result space for explicit conversion of FLOAT value '3.8833137793643' to a VARCHAR field.
The query:
INSERT INTO TableA
SELECT DISTINCT max(price_1) AS PriceValue
FROM TableB
This does may or may not answer your question. But the query should be written as:
INSERT INTO TableA (<column name>)
SELECT MAX(price_1) AS PriceValue
FROM TableB;
Notes:
An aggregation query with no GROUP BY returns exactly one row. SELECT DISTINCT is not necessary.
You should include the columns being inserted.
Your problem is clearly that the column is not wide enough. If you have defined the table as:
create table tableA (
col varchar
);
Then you have not specified a length and are depending on the default in the database. Do you even know what the default is? In this case, it is 1. And that is not long enough for your value. You just need to provide a long-enough length:
create table tableA (
col varchar(255)
);
All that said. I strongly discourage you from storing number values as strings. That is likely to create problems now and in the future. Use the appropriate types for your data.

SQL secondary headers within data

I am having an issue that I haven't found an answer to. I wrote an SQL Query to generate a report that runs fine and outputs mostly numeric fields. The issue I'm running into is that we are putting it into a program that emails out files and it can only email out a .csv that does not include the header rows.
Is there a way to input the headers into the data? I've found a few solutions on here that didn't work for me. It seems like no matter what I do I get a data type error. This is all on an Oracle Database, the program we are using to send data out is called IQAlert, it's part of IQMS which is a manufacturing/erp system.
So far I've tried casting the headers as a number of numerical fields, a number of other solutions I found on here and other places on the internet such as changing to titles to varchar. The error I'm currently getting is
"ORA-01790: expression must have the same datatype as corresponding
expression"
Here is an extremely parsed down sample of the code. Adding the title "itemno' works fine because that field is text, when I try to add the header to onhand I get the data type error referenced above.
select 'itemno' as itemno, 'OnHand' as OnHand
from iqms.arinvt
union
select arinvt.itemno, arinvt.onhand
from iqms.arinvt
where itemno='10-00000000'
According to the documentation regarding The UNION [ALL], INTERSECT, MINUS Operators
You can combine multiple queries using the set operators UNION, UNION
ALL, INTERSECT, and MINUS. All set operators have equal precedence. If
a SQL statement contains multiple set operators, then Oracle Database
evaluates them from the left to right unless parentheses explicitly
specify another order.
The corresponding expressions in the select lists of the component
queries of a compound query must match in number and must be in the
same data type group (such as numeric or character).
If component queries select character data, then the data type of the
return values are determined as follows:
If both queries select values of data type CHAR of equal length, then
the returned values have data type CHAR of that length. If the queries
select values of CHAR with different lengths, then the returned value
is VARCHAR2 with the length of the larger CHAR value.
If either or both of the queries select values of data type VARCHAR2,
then the returned values have data type VARCHAR2.
If component queries select numeric data, then the data type of the
return values is determined by numeric precedence:
If any query selects values of type BINARY_DOUBLE, then the returned
values have data type BINARY_DOUBLE.
If no query selects values of type BINARY_DOUBLE but any query selects
values of type BINARY_FLOAT, then the returned values have data type
BINARY_FLOAT.
If all queries select values of type NUMBER, then the returned values
have data type NUMBER.
In queries using set operators, Oracle does not perform implicit
conversion across data type groups. Therefore, if the corresponding
expressions of component queries resolve to both character data and
numeric data, Oracle returns an error.
In short: in a query using one of the SET operators, for example like this:
SELECT x FROM table
UNION
SELECT y FROM table
where x is of numeric datatype, and yis of character datatype (or vice versa), then Oracle does not perform implicit conversion across data type groups and returns an error
Two simple examples:
SELECT 1 as X FROM dual
UNION
SELECT 'John' as Y FROM dual
ORA-01790: expression must have same datatype as corresponding expression
SELECT 'John' as X FROM dual
UNION ALL
SELECT 123 as Y FROM dual;
ORA-01790: expression must have same datatype as corresponding expression
Because Oracle does not perform implicit conversion, you must do an explicit conversion of one datatype to another datatype, the easiest one is to convert numbers to strings using TO_CHAR conversion function, like in this example:
SELECT 'John' as X FROM dual
UNION ALL
SELECT to_char(123) as Y FROM dual;
X
----
John
123
Maybe this will help. The first number is just sequence, the ROWNUM or ROW_NUMBER() can be used instead. The rest of numbers is simulated values:
SELECT itemno, onhand FROM
(
select 1 row_seq, NULL itemno, to_number(null) onhand from dual
union all
select 2, '5', 6 from dual
union all
select 3, '7', 8 from dual
)
WHERE row_seq > 1
/
Output:
ITEMNO ONHAND
5 6
7 8

UNION causes "Conversion failed when converting the varchar value to int"

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.