Oracle SQL Cast two different columns to one column? - sql

I am selecting data from two different columns depending on what sort of record it is.
Using a Case statement I check what type of record it is and select the appropriate column to insert.
However the syntax for using CAST is not correct and after checking the Oracle docs, there is no reason why it is not working.
CREATE TABLE TEST123 AS
SELECT DISTINCT
bill.ROW_ID,
bill.ACCNT_TYPE_CD,
CASE
WHEN bill.ACCNT_TYPE_CD = 'TestAccount'
THEN CAST(TO_CHAR(bill.INTEGRATION_ID) AS VARCHAR2(30)) AS NUM
ELSE CAST(TO_CHAR(bill.OU_NUM )AS VARCHAR2(30)) AS NUM
END
FROM SIEBEL.S_ORG_EXT bill
INNER JOIN Products prod
ON prod.BILL_ACCNT_ID = bill.ROW_ID
OR prod.CUST_ACCNT_ID = bill.ROW_ID;
Error code is:
ORA-00905: missing keyword
00905. 00000 - "missing keyword"

AS NUM must follow the END of the CASE. If you could set the column name for each condition separately, then the column could have two different names. Clearly that can't work.
CASE
WHEN bill.ACCNT_TYPE_CD = 'TestAccount'
THEN CAST(TO_CHAR(bill.INTEGRATION_ID) AS VARCHAR2(30))
ELSE CAST(TO_CHAR(bill.OU_NUM )AS VARCHAR2(30))
END AS NUM
Also, using both TO_CHAR and CAST(... as VARCHAR(30)) is redundant. They are both ways of converting a non-string to a string.

And since CASE .. END is a function, you can go even further than explained by Allan:
SELECT DISTINCT ...
CAST(
CASE WHEN bill.ACCNT_TYPE_CD = 'TestAccount'
THEN bill.INTEGRATION_ID
ELSE bill.OU_NUM
END
AS VARCHAR(30) -- `AS` here is part of the `CAST` function
-- and will denote the requested data type
) AS NUM -- `AS` here introduces the column alias
If your not familiar with the CAST function, please beware of the double meaning of the AS keyword here. See the comments in the code above

Related

Use table in order by case when does not work

I am running this query but I get an error
select *
from dog
order by case
when exists(
select 1 from dogfood where dog.dogid = dogfood.dogid)
then '1'
else '0' end;
So 2 tables, dog and dogfood which both have a dogid column. I get this error:
[42703][-206] "DOG.DOGID" is not valid in the context where
it is used.. SQLCODE=-206, SQLSTATE=42703, DRIVER=4.26.14
[56098][-727] An error occurred during implicit system action type
"2". Information returned for the error includes SQLCODE "-206",
> SQLSTATE "42703" and message tokens "DOG.DOGID"..
> SQLCODE=-727, SQLSTATE=56098, DRIVER=4.26.14
I just want to order the dog by if it has a row in dogfood. A solution would be querying the result in the select clause and refer to it in the order by clause, but I want it in the order by clause for my application. I am curious why this query isn't working, I double checked for syntax errors but I could not find any. Am I missing something obvious? I would expect I could refer to a table in the order by which I queried in the select/from clauses.
See documentation
sort-key-expression
An expression that is not simply a column name or an unsigned integer constant. The query to which ordering is applied must be a
subselect to use this form of sort-key. The sort-key-expression cannot
include a correlated scalar fullselect (SQLSTATE 42703) or a function
with an external action (SQLSTATE 42845).
But since it is not correlated you can use IN with a fullselect
select *
from dog
order by
case when dog.dogid in (select dogid from dogfood)
then '1' else '0' end;

Snowflake case statement is returning an error instead of the value specified within the ELSE clause

I need to check if one or many fields already exists in a table so I can do a merge into statement using them.
I tried this:
select sat_sector_hkey,
CASE
WHEN EXISTS(select id from hub_sector)
THEN (MERGE INTO ...)
END AS id
from sat_sector;
For testing, I used only one case statement, and replaced merge into with a THEN...ELSE values:
SELECT sat_sector_hkey,
CASE
WHEN EXISTS(select id from hub_sector)
THEN '1'
ELSE ''
END AS id
FROM sat_sector;
When this field does not exists, the query return an error instead of '':
SQL compilation error: error line 3 at position 23 invalid identifier
'ID'
I am using a CASE, because I need to check if a column exists or not, as I don't know if it exists or not due to some technicalities in our data coming from multiple sources.
Try this:
Construct an object with the full row.
Test if the constructed object has data for "ID".
create or replace temp table maybe_id
as
select 1 x, 2 id;
select *,
case
when object_construct(a.*):ID is not null
then '1'
else ''
end as id
from maybe_id a
;
Works for me - it gives 1 when the column id has data, and `` when the column doesn't exist in the table.

Issue with Postgres not recognizing CAST on join

I'm trying to join two tables together based on an ID column. The join is not working successfully because I cannot join a varchar column on an integer column, despite using cast().
In the first table, the ID column is character varying, in the format of: XYZA-123456.
In the second table, the ID column is simply the number: 123456.
-- TABLE 1
create table fake_receivers(id varchar(11));
insert into fake_receivers(id) values
('VR2W-110528'),
('VR2W-113640'),
('VR4W-113640'),
('VR4W-110528'),
('VR2W-110154'),
('VMT2-127942'),
('VR2W-113640'),
('V16X-110528'),
('VR2W-110154'),
('VR2W-110528');
-- TABLE 2
create table fake_stations(receiver_sn integer, station varchar);
insert into fake_stations values
('110528', 'Baff01-01'),
('113640', 'Baff02-02'),
('110154', 'Baff03-01'),
('127942', 'Baff05-01');
My solution is to split the string at the dash, take the number after the dash, and cast it as an integer, so that I may perform the join:
select cast(split_part(id, '-', 2) as integer) from fake_receivers; -- this works fine, seemingly selects integers
However, when I actually attempt to perform the join, I'm getting the following error, despite using an explicit cast:
select cast(split_part(id, '-', 2) as integer), station
from fake_receivers
inner join fake_locations
on split_part = fake_locations.receiver_sn -- not recognizing split_part cast as integer!
>ERROR: operator does not exist: character varying = integer
>Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Strangely enough, I can perform this join with my full dataset (a queried result set shows up) but I then can't manipulate it at all (e.g. sorting, filtering it) - I get an error saying ERROR: invalid input syntax for integer: "UWM". The string "UWM" appears nowhere in my dataset or in my code, but I strongly suspect it has to do with the split_part cast from varchar to integer going wrong somewhere.
-- Misc. info
select version();
>PostgreSQL 10.5 on x86_64-apple-darwin16.7.0, compiled by Apple LLVM version 9.0.0 (clang-900.0.39.2), 64-bit
EDIT: dbfiddle exhibiting behavior
You need to include your current logic directly in the join condition:
select *
from fake_receivers r
inner join fake_stations s
on split_part(r.id, '-', 2)::int = s.receiver_sn;
Demo

Why can't i refer to a column alias in the ORDER BY using CASE?

Sorry if this a duplicate, but i haven't found one. Why can't i use my column alias defined in the SELECT from the ORDER BY when i use CASE?
Consider this simple query:
SELECT NewValue=CASE WHEN Value IS NULL THEN '<Null-Value>' ELSE Value END
FROM dbo.TableA
ORDER BY CASE WHEN NewValue='<Null-Value>' THEN 1 ELSE 0 END
The result is an error:
Invalid column name 'NewValue'
Here's a sql-fiddle. (Replace the ORDER BY NewValue with the CASE WHEN... that´'s commented out)
I know i can use ORDER BY CASE WHEN Value IS NULL THEN 1 ELSE 0 END like here in this case but actually the query is more complex and i want to keep it as readable as possible. Do i have to use a sub-query or CTE instead, if so why is that so?
Update as Mikael Eriksson has commented any expression in combination with an alias is not allowed. So even this (pointless query) fails for the same reason:
SELECT '' As Empty
FROM dbo.TableA
ORDER BY Empty + ''
Result:
Invalid column name 'Empty'.
So an alias is allowed in an ORDER BY and also an expression but not both. Why, is it too difficult to implement? Since i'm mainly a programmer i think of aliases as variables which could simple be used in an expression.
This has to do with how a SQL dbms resolves ambiguous names.
I haven't yet tracked down this behavior in the SQL standards, but it seems to be consistent across platforms. Here's what's happening.
create table test (
col_1 integer,
col_2 integer
);
insert into test (col_1, col_2) values
(1, 3),
(2, 2),
(3, 1);
Alias "col_1" as "col_2", and use the alias in the ORDER BY clause. The dbms resolves "col_2" in the ORDER BY as an alias for "col_1", and sorts by the values in "test"."col_1".
select col_1 as col_2
from test
order by col_2;
col_2
--
1
2
3
Again, alias "col_1" as "col_2", but use an expression in the ORDER BY clause. The dbms resolves "col_2" not as an alias for "col_1", but as the column "test"."col_2". It sorts by the values in "test"."col_2".
select col_1 as col_2
from test
order by (col_2 || '');
col_2
--
3
2
1
So in your case, your query fails because the dbms wants to resolve "NewValue" in the expression as a column name in a base table. But it's not; it's a column alias.
PostgreSQL
This behavior is documented in PostgreSQL in the section Sorting Rows. Their stated rationale is to reduce ambiguity.
Note that an output column name has to stand alone, that is, it cannot be used in an expression — for example, this is not correct:
SELECT a + b AS sum, c FROM table1 ORDER BY sum + c; -- wrong
This restriction is made to reduce ambiguity. There is still ambiguity if an ORDER BY item is a simple name that could match either an output column name or a column from the table expression. The output column is used in such cases. This would only cause confusion if you use AS to rename an output column to match some other table column's name.
Documentation error in SQL Server 2008
A slightly different issue with respect to aliases in the ORDER BY clause.
If column names are aliased in the SELECT list, only the alias name can be used in the ORDER BY clause.
Unless I'm insufficiently caffeinated, that's not true at all. This statement sorts by "test"."col_1" in both SQL Server 2008 and SQL Server 2012.
select col_1 as col_2
from test
order by col_1;
It seems this limitation is related to another limitation in which "column aliases can't be referenced in same SELECT list". For example, this query:
SELECT Col1 AS ColAlias1 FROM T ORDER BY ColAlias1
Can be translated to:
SELECT Col1 AS ColAlias1 FROM T ORDER BY 1
Which is a legal query. But this query:
SELECT Col1 AS ColAlias1 FROM T ORDER BY ColAlias1 + ' '
Should be translated to:
SELECT Col1 AS ColAlias1, ColAlias1 + ' ' FROM T ORDER BY 2
Which will raise the error:
Unknown column 'ColAlias1' in 'field list'
And finally it seems these are because of SQL standard behaviours not an impossibility in implementation.
More info at: Here
Note: The last query can be executed by MS Access without error but will raise the mentioned error with SQL Server.
You could try something like:
select NewValue from (
SELECT (CASE WHEN Value IS NULL THEN '<Null-Value>' ELSE Value END ) as NewValue,
( CASE WHEN NewValue='<Null-Value>' THEN 1 ELSE 0 END) as ValOrder
FROM dbo.TableA
GROUP BY Value
) t
ORDER BY ValOrder

Check if field is numeric, then execute comparison on only those field in one statement?

This may be simple, but I am no SQL whiz so I am getting lost. I understand that sql takes your query and executes it in a certain order, which I believe is why this query does not work:
select * from purchaseorders
where IsNumeric(purchase_order_number) = 1
and cast(purchase_order_number as int) >= 7
MOST of the purchar_order_number fields are numeric, but we introduce alphanumeric ones recently. The data I am trying to get is to see if '7' is greater than the highest numeric purchase_order_number.
The Numeric() function filters out the alphanumeric fields fine, but doing the subsequent cast comparison throws this error:
Conversion failed when converting the nvarchar value '124-4356AB' to data type int.
I am not asking what the error means, that is obvious. I am asking if there is a way to accomplish what I want in a single query, preferably in the where clause due to ORM constraints.
does this work for you?
select * from purchaseorders
where (case when IsNumeric(purchase_order_number) = 1
then cast(purchase_order_number as int)
else 0 end) >= 7
You can do a select with a subselect
select * from (
select * from purchaseorders
where IsNumeric(purchase_order_number) = 1) as correct_orders
where cast(purchase_order_number as int) >= 7
try this:
select * from purchaseorders
where try_cast(purchase_order_number as int) >= 7
have to check which column has numeric values only.
Currently, in a table every field is setted with nvarchar(max) Like tableName (field1 nvarchar(max),field2 nvarchar(max),field3 nvarchar(3)) and tableName has 25lac Rows.
But on manually Check Field2 Contain the numeric Values Only... How to Check With t-sql that in the Complete Column (Field2) has numeric Value or not/null value with Longest Length in the Column!