Using Cast on Left Join to Change VARCHAR to DECIMAL - sql

I need to join a table using a user defined column (UDF1) that contains text data and account numbers to another table on account numbers (LDACCT). The account numbers should be formatted as decimal(16,0), but the column UDF1 has text data in it (as well as account numbers) because UDF1 is also used for purposes other than to house account numbers (not my design). My current join isn't working:
left outer join dbo.tbl_Loan_Legal_Descriptions as ll2
on CAST(uf.UDF1 as decimal(16, 0)) = ll2.LDACCT
I'm getting the dreaded: Error converting data type varchar to numeric, and I can't seem to modify the join to resolve the error. Any suggestions would be greatly appreciated.

Please change the "on" part as:
on CAST(uf.UDF1 as varchar(255)) = cast(ll2.LDACCT as varchar(255))

Maybe one of your rows in uf has something in it that can't be cast to a decimal. Try
select
*
from uf
where left(uf.UDF1,1) not in ('0','1','2','3','4','5','6','7','8','9')
Depending on whether you want to ignore that row, you can either try to exclude that row through other criteria, or you can turn the join around, casting the other side to a string:
...
left outer join dbo.tbl_Loan_Legal_Descriptions as ll2
on uf.UDF1 = cast(varchar,ll2.LDACCT)
If you try that, you might need to strip leading zeroes from uf.UDF1, but as you did not show us any representative data from the tables, all we can do here is just guess or caution about it.

Related

SELECT query error ORA-01722 (invalid number)

I am facing this error message with my query and can't manage to figure it out. Can anyone take a look at my query and share some insights? Thanks a lot
Oracle database
SELECT BB_BB60.USERS.FIRSTNAME, BB_BB60.USERS.LASTNAME,
BB_BB60.USERS.STUDENT_ID AS IDNUMBER, BB_BB60.USERS.USER_ID AS USERNAME,
REPLACE(CRSADMIN.OCCURRENCE.CODE, '/','_') AS DESCRIPTION,
'Moodle_2019' AS PASSWORD,
SUBSTR(BB_BB60.COURSE_MAIN.COURSE_ID, 0, 7) AS DEPARTMENT
FROM (CRSADMIN.OCCURRENCE
INNER JOIN CRSADMIN.REQ_OCC ON CRSADMIN.OCCURRENCE.PK = CRSADMIN.REQ_OCC.OCC_PK1)
INNER JOIN ((BB_BB60.COURSE_USERS INNER JOIN BB_BB60.COURSE_MAIN ON BB_BB60.COURSE_USERS.CRSMAIN_PK1 = BB_BB60.COURSE_MAIN.PK1)
INNER JOIN BB_BB60.USERS ON BB_BB60.COURSE_USERS.USERS_PK1 = BB_BB60.USERS.PK1) ON CRSADMIN.REQ_OCC.REQ_PK1 = BB_BB60.COURSE_MAIN.PK1
WHERE (((BB_BB60.COURSE_MAIN.COURSE_ID) = 'PARA602_2019_02'));
The likely problem is with your data model. In at least one of your JOIN criteria you are joining a numeric column to a varchar2 column, which leads to an implicit casting to a number. However, your varchar2 column contains strings which aren't numeric, consequently the join hurls ORA-01722.
Without knowing your table structures we can't identify the problem columns so you'll need to figure it out for yourself.
One solution would be to cast the numeric column to a string e.g.
on t1.vcol_pk = to_char(t2.ncol_pk)
This might have performance implications (the optimiser won't use the index on t2.ncol_pk).
A better solution would be to fix the data model so you don't need to compare strings and numbers, and also clear up your data.

Oracle Invalid Number in Join Clause

I am getting an Oracle Invalid Number error that doesn't make sense to me. I understand what this error means but it should not be happening in this case. Sorry for the long question, but please bear with me so I can explain this thoroughly.
I have a table which stores IDs to different sources, and some of the IDs can contain letters. Therefore, the column is a VARCHAR.
One of the sources has numeric IDs, and I want to join to that source:
SELECT *
FROM (
SELECT AGGPROJ_ID -- this column is a VARCHAR
FROM AGG_MATCHES -- this is the table storing the matches
WHERE AGGSRC = 'source_a'
) m
JOIN SOURCE_A a ON a.ID = TO_NUMBER(m.AGGPROJ_ID);
In most cases this works, but depending on random things such as what columns are in the select clause, if it uses a left join or an inner join, etc., I will start seeing the Invalid Number error.
I have verified multiple times that all entries in AGG_MATCHES where AGGSRC = 'source_a' do not contain non numeric characters in the AGGPROJ_ID column:
-- this returns no results
SELECT AGGPROJ_ID
FROM AGG_MATCHES
WHERE AGGSRC = 'source_a' AND REGEXP_LIKE(AGGPROJ_ID, '[^0-9]');
I know that Oracle basically rewrites the query internally for optimization. Going back to the first SQL example, my best guess is that depending on how the entire query is written, in some cases Oracle is trying to perform the JOIN before the sub query. In other words, it's trying to join the entire AGG_MATCHES tables to SOURCE_A instead of just the subset returned by the sub query. If so, there would be rows that contain non numeric values in the AGGPROJ_ID column.
Does anyone know for certain if this is what's causing the error? If it is the reason, is there anyway for me to force Oracle to execute the sub query part first so it's only trying to join a subset of the AGG_MATCHES table?
A little more background:
This is obviously a simplified example to illustrate the problem. The AGG_MATCHES table is used to store "matches" between different sources (i.e. projects). In other words, it's used to say that a project in sourceA is matched to a project in sourceB.
Instead of writing the same SQL over and over, I've created views for the sources we commonly use. The idea is to have a view with two columns, one for SourceA and one for SourceB. For this reason, I don't want to use TO_CHAR on the ID column of the source table, because devs would have to remember to do this every time they are doing a join, and I'm trying to remove code duplication. Also, since the ID in SOURCE_A is a number, I feel that any view storing SOURCE_A.ID should go ahead and convert it to a number.
You are right that Oracle is executing the statement in a different order than what you wrote, causing conversion errors.
The best ways to fix this problem, in order, are:
Change the data model to always store data as the correct type. Always store numbers as numbers, dates as dates, and strings as strings. (You already know this and said you can't change your data model, this is a warning for future readers.)
Convert numbers to strings with a TO_CHAR.
If you're on 12.2, convert strings to numbers using the DEFAULT return_value ON CONVERSION ERROR syntax, like this:
SELECT *
FROM (
SELECT AGGPROJ_ID -- this column is a VARCHAR
FROM AGG_MATCHES -- this is the table storing the matches
WHERE AGGSRC = 'source_a'
) m
JOIN SOURCE_A a ON a.ID = TO_NUMBER(m.AGGPROJ_ID default null on conversion error);
Add a ROWNUM to an inline view to prevent optimizer transformations that may re-write statements. ROWNUM is always evaluated at the end and it forces Oracle to run things in a certain order, even if the ROWNUM isn't used. (Officially hints are the way to do this, but getting hints right is too difficult.)
SELECT *
FROM (
SELECT AGGPROJ_ID -- this column is a VARCHAR
FROM AGG_MATCHES -- this is the table storing the matches
WHERE AGGSRC = 'source_a'
--Prevent optimizer transformations for type safety.
AND ROWNUM >= 1
) m
JOIN SOURCE_A a ON a.ID = TO_NUMBER(m.AGGPROJ_ID);
I think the simplest solution uses case, which has more guarantees on the order of evaluation:
SELECT a.*
FROM AGG_MATCHES m JOIN
SOURCE_A a
ON a.ID = (CASE WHEN m.AGGSRC = 'source_a' THEN TO_NUMBER(m.AGGPROJ_ID) END);
Or, better yet, convert to strings:
SELECT a.*
FROM AGG_MATCHES m JOIN
SOURCE_A a
ON TO_CHAR(a.ID) = m.AGGPROJ_ID AND
m.AGGSRC = 'source_a' ;
That said, the best advice is to fix the data model.
Possibly the best solution in your case is simply a view or a generate column:
create view v_agg_matches_a as
select . . .,
(case when regexp_like(AGGPROJ_ID, '^[0-9]+$')
then to_number(AGGPROJ_ID)
end) as AGGPROJ_ID
from agg_matches am
where m.AGGSRC = 'source_a';
The case may not be necessary if you use a view, but it is safer.
Then use the view in subsequent queries.

ssrs error converting data type nvarchar to int

I passed this stored procedure into ssrs to generate a report but kept getting error converting data type nvarchar to int, while i don't even have any parameter that's nvarchar type.
Alter proc dbo.spPullOrderRosa1
#Subentity int,
#BegShipDate date,
#EndShipDate date,
#Store varchar(150),
#State varchar(150)
as
begin
select OpOrID as OrID, OpID, concat(OrCuFirstName,' ',OrCuLastName) as CustomerName,
b.SoName as StoreName,OpPrSKU as SKU, OpQty,StLongName as StateName,
cast(OpShipDate as date) as ShipDate,
cast(d.DeliveryDate as date) as DeliveryDate,
e.StyName as SubEntity
from csn_order..tblOrderProduct a with (nolock)
left join csn_order..tblOrder f with (nolock) on a.OpOrID = f.OrID
left join csn_order..tblStore b with (nolock) on a.OpSoID = b.SoID
left join csn_order..tblplState c with (nolock) on f.OrCuStID = c.StID
left join csn_order..tblDeliveryDate d with (nolock) on a.OpID = d.DeliveryOpID
left join csn_order.dbo.tblSubEntity e with (nolock) on b.SoStyID = e.StyID
where (OpCancelled = 0) and (b.SoID in (select SoID from csn_order..tblStore where SoName in (select * from STRING_SPLIT(#Store, ',')) ))
and (StID in (select StID from csn_order..tblplState where StLongName in (select * from STRING_SPLIT(#State, ',')) ))
and (StyID = #Subentity) and (OpShipDate >= #BegShipDate and OpShipDate <= #EndShipDate)
end
I definitely would not write it off as just random, you don't want this popping back up when certain conditions are met. Here are a few things I'd try to narrow it down
1) You use LEFT JOINs, it can leave NULL values in fields you expect to be integers (like QTY), try wrapping them in COALESCE statements in your SELECT clause
SELECT COALESCE(OpQty, 0) as OpQty, ...
2) SSRS might be guessing the data type wrong, it might think a character field is an integer if the first few values are numbers. Figure out which field is generating the error, and perhaps cast it explicitly to NVARCHAR so SSRS won't try to use it as an integer
SELECT CONVERT(nvarchar(50), OpPrSKU) as SKU, ...
3) SSRS might have added a "TOTAL" field at the end of a DETAIL group, so it's trying to do math on a field that isn't a number. This is less likely, but possible so at least worth looking for.
But the important thing is to figure out WHICH field is generating the error so you can focus your attention on it.
EDIT: If you're using SQL Server 2012 or later, you can also explicitly set the data types returned using the EXECUTE WITH RESULT SETS clause in your dataset in the report. A good example is http://www.sqlservercentral.com/blogs/sqlstudies/2016/01/14/what-is-result-sets/
Note that this has the disadvantage that if you update the stored procedure definition to include more columns, you must remember to track down and update all reports that use it. If your setting doesn't change SP definitions then it's not an issue and is the most reliable way to tell SSRS what the right types are, but for me casting the type inside the SP is more flexible in the long run and is enough for SSRS in every case I've encountered.
Just to put my 2 cents in (Knowing this post is already over 2 years old) and I am not saying this will work for everyone. I was experiencing the same issue as OP.
I created a new rdl file and copied over all the objects.

SQL Server 2005 Data Types - Struggling to get views working with current data types

I am in the middle of creating a new database for mobile phones. It includes a lot of information regarding mobile phones, sim cards etc. I am struggling to get the information in the tables converted into a view. I have done a few tests but always receive an error on certain columns. For example, one of the fields is the sim card number which you'll all know is a long number. I have tried having this number as bigint, varchar and nvarchar but always receive an error saying "the conversion of the varchar value 'value' has overflowed an int column. Maximum integer value exceeded".
I have a decent level of knowledge when it comes to databases but for some reason I just can't seem to find the right data type for these fields. If someone who has a lot more experience in this could help me out, it would be much appreciated.
Thanks in advance.
SELECT dbo.Sims.Number,
dbo.Sims.ACCOLC,
dbo.Users.Title,
dbo.Users.Name,
dbo.Users.Section,
dbo.Users.Directorate,
dbo.UserHistory.StartDate,
dbo.UserHistory.EndDate,
dbo.Users.Codes
FROM dbo.UserHistory
INNER JOIN dbo.Users
ON dbo.UserHistory.[User] = dbo.Users.ID
INNER JOIN dbo.Sims
ON dbo.UserHistory.Number = dbo.Sims.Number
INNER JOIN dbo.Models
ON dbo.UserHistory.Model = dbo.Models.ID
The one thing that I might suggest is to check if you in fact want an INNER JOIN between each table. That requires matching rows in all tables, if you do not have the matching row then you won't get a result.
You might want to try changing the JOIN type to a LEFT JOIN:
SELECT s.Number,
s.ACCOLC,
u.Title,
u.Name,
u.Section,
u.Directorate,
uh.StartDate,
uh.EndDate,
uh.Codes
FROM dbo.Users u
LEFT JOIN dbo.UserHistory uh
ON u.ID = uh.[User]
LEFT JOIN dbo.Sims s
ON uh.Number = s.Number
LEFT JOIN dbo.Models m
ON uh.Model = m.ID
This version will return all users even it there are not matching rows in the other tables.

Not able to left join two tables using a non numeric column? ora-01722

I would like to check, is it possible to left join two tables using a non numeric column?
i.e. where descriptions_cd is a varchar(10) and table_cd is a varchar(10):
SELECT *
FROM descriptions d
LEFT JOIN tables t ON t.table_cd = d.descriptions_cd;
This SQL seems to be giving an ora-01722 error. This is in Oracle 9i.
Can you check values of one of these column contain only numeric data (even if the volumn type is varchar) ?
ok, table_cd is not numeric. that explains.