SELECT query error ORA-01722 (invalid number) - sql

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.

Related

Postgresql, sql command, join table with similar string, only string "OM:" is at the begin

I wanna join table.
left join
c_store on o_order.customer_note = c_store.store_code
String in field is almost same, just contains "OM:" on start of field, for example, field from o_order.customer_note is
OM:4008
and from c_store.store_code is
4008
Is possible to join table c_store.store_code based on remove (or replace ) from every field in o_order.customer_note?
I tried
c_store on replace(o_order.customer_note, '', 'OM:') = c_store.store_code
but no success. I think, this is only for rename column name, right? Sorry for this question, I am new in this.
Thanks.
Use a string concatenation in your join condition:
SELECT ...
FROM o_order o
LEFT JOIN c_store c
ON o.customer_note = 'OM:' || c.store_code::text;
But not that while the above logic might fix your query in the short term, in the long term the better fix would be to have proper join columns setup in your database. That is, it is desirable to be able to do joins on equality alone. This would let Postgres use an index, if it exists.

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.

Using Cast on Left Join to Change VARCHAR to DECIMAL

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.

SQL Server distinct not being used properly

I'm trying to select just one account using SQL Server but am getting the following error:
ERROR: The text data type cannot be selected as DISTINCT because
it is not comparable. Error Code: 421
with the following statement:
select DISTINCT ad.*,
acc.companyname,
acc.accountnumber
from address ad
join AddressLink al on al.AddressID = ad.id
join account acc on acc.ID = al.ParentID
where acc.accountnumber like '11227'
What have I done wrong?
Edit:
New query:
select address.ID,
address.StreetAddress1,
address.StreetAddress2,
address.City,
Address.State,
Address.PostalCode,
Address.ClassTypeID,
account.companyname,
account.accountnumber,
addresslink.ID as addressLinkID,
addresslink.addresstypeid
from address
join AddressLink on address.id = addresslink.AddressID
join account on addresslink.ParentID = account.ID
where account.CompanyName like 'company name'
All the company names that I've had to blur are identical.
Try:
select ad.*,
l.companyname,
l.accountnumber
from address ad
join (select DISTINCT al.AddressID,
acc.companyname,
acc.accountnumber
from account acc
join AddressLink al on acc.ID = al.ParentID
where acc.accountnumber like '11227') l
on l.AddressID = ad.id
"Distinct", in the context you have is trying to do distinct on ALL columns. That said, there are some data types that are NOT converable, such as TEXT. So, if your table has some of these non "Distinctable" column types exists, that is what is crashing your query.
However, to get around this, if you do something like
CONVERT( char(60), YourTextColumn ) as YourTextColumn,
It should get that for you... at least its now thinking the final column type is "char"acter and CAN compare it.
You should check the data types of the columns in the address table. My guess is that one or more of them has the data type text, ntext or image.
One of the restrictions of using text, ntext or image data types is that columns defined of these data types cannot be used as part of a SELECT statement that includes the DISTINCT clause.
For what it's worth, the MSDN article for ntext, text, and image (Transact-SQL) recommends avoiding these data types and use nvarchar(max), varchar(max), and varbinary(max) instead. You may want to consider changing how that table is defined.
The accepted answer from Mark B shows a subquery (good idea to limit the domain of the DISTINCT) on AddressLink.AddressId, Account.CompanyName, and Account.AccountNumber.
Let me ask this: Does AddressLink allow more than one record to have the same value in the ParentId and AddressId fields?
If not, and assuming that Mark B's answer works, then just remove the DISTINCT because you're never going to get any duplicates inside of that subquery.
Leaving the DISTINCT in causes a performance hit because the DB has to create a temporary table that is either indexed with a btree or a hash and it has to insert every value returned by the subquery into that table to check if it invalidates the uniqueness constraint on those three fields. Note that the "optimizer" doesn't know that there won't be any dupes... if you tell it to check for DISTINCT, it will check it... With a btree index this is going to cause O(n log n) work on the number of rows returned; with a hash it would cause O(n) work but who knows how big the constant factor is in relation to the other work you're doing (it's probably larger than everything else you're doing meaning this could make this run half as fast as without the DISTINCT).
So my answer is Mark B's answer without the DISTINCT in the subquery. Let me know if AddressLink does allow repeats (can't imagine why it would).

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.