SQL secondary headers within data - sql

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

Related

Unioned select statements cause an int overflow error

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.

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.

Conversion failed when converting the varchar value '1 BOX ' to data type int

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.

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.

Conversion failed when converting the varchar value '1,' to data type int

I have table categories (c) and an another table (x) with a column which can contain cat IDs separated with comma as varchar data type. I want to Select related categories but I'm having error "Conversion failed when converting the varchar value '5,' to data type int." when trying to select:
SELECT ID, Title FROM c WHERE ID IN (SELECT catIDs FROM x WHERE ID=any);
The subquery returns data like "1,3,4"
You need to split the 1,3,4 string returned by the subquery into separate int values. SQL Server does not have a built-in function to do it, but you can use this user-defined function.
Create the function dbo.Split in your database and then re-write your query as follows:
SELECT ID, Title
FROM c
WHERE ID IN
(
SELECT s
FROM dbo.Split(',', '1,3,4')
)
I replaced the subquery with example results 1,3,4 to shorten the query and make it easier to understand.
If I get it right, you actually have values like "1,3,4" in your column catIDs. So you should extract a substring in the select of your subquery.
By the way, I'm not an MS SQL Server expert, but it's probably a bad database design to do so. I'm not sure the RDBMS engine will use indexes in such a case...