1

I have an Oracle database, and I need to change a NUMBER(38,0) column to a VARCHAR2 column in one of the tables. At the advice of this post, I'm doing the following:

  1. Add a temp column of type VARCHAR2
  2. Copy the data from the original NUMBER column to the temp column
  3. Drop the original NUMBER column
  4. Rename the temp column to original column name

However, step 2 causes the subject error, even though the copy is from NUMBER to VARCHAR2.

As a safeguard, I'm running my code below on a copy of the table to be altered, which I created using:

create table TPA_SPEC_COPY as select * from TPA_SPEC;
COMMIT WORK;

Here is my SQL code trying to perform the steps above:

ALTER TABLE TPA_SPEC_COPY
ADD (PA_SPEC_VALUE_NUM_TEMP  VARCHAR2(40 CHAR));

UPDATE TPA_SPEC_COPY set PA_SPEC_VALUE_NUM_TEMP = TO_CHAR(PA_SPEC_VALUE_NUM);  -- This is Line 4 where I get the error

ALTER TABLE TPA_SPEC_COPY DROP COLUMN PA_SPEC_VALUE_NUM_TEMP;

ALTER TABLE TPA_SPEC_COPY 
RENAME COLUMN PA_SPEC_VALUE_NUM_TEMP TO PA_SPEC_VALUE_NUM;

This is the error I am receiving in SQL Developer:

Error starting at line : 4 in command -
UPDATE TPA_SPEC_COPY set PA_SPEC_VALUE_NUM_TEMP = TO_CHAR(PA_SPEC_VALUE_NUM)
Error report -
SQL Error: ORA-01722: invalid number
01722. 00000 -  "invalid number"
*Cause:    The specified number was invalid.
*Action:   Specify a valid number.

EDIT: Adding the table structure (using DESCRIBE TPA_SPEC_COPY)

DESCRIBE TPA_SPEC_COPY
Name                     Null     Type               
------------------------ -------- ------------------ 
PA_ID                    NOT NULL NUMBER(10)         
PA_VERSION_NUM           NOT NULL NUMBER(10)         
PA_SPEC_VERSION_NUM      NOT NULL NUMBER(10)         
SPEC_TYPE_CD             NOT NULL CHAR(10 CHAR)      
PA_SPEC_VALUE_NUM                 NUMBER(38)         
UOM_CD                            CHAR(10 CHAR)      
PA_SPEC_FORMULA_TXT               VARCHAR2(100 CHAR) 
PA_SPEC_COMMENT_TXT               VARCHAR2(250 CHAR) 
DISPLAY_FORMAT_NM                 VARCHAR2(30 CHAR)  
ROW_PROG_UPDT_ID         NOT NULL CHAR(12 CHAR)      
ROW_STATUS_CD            NOT NULL CHAR(1 CHAR)       
ROW_UPDATE_TIME          NOT NULL TIMESTAMP(9)       
ROW_LASTUPD_USERID       NOT NULL VARCHAR2(80 CHAR)  
ROW_CREATE_TIME          NOT NULL TIMESTAMP(9)       
ROW_CREATE_USERID        NOT NULL VARCHAR2(80 CHAR)  
VARIABLE_ID                       VARCHAR2(100 CHAR) 
SPEC_FORMULA_NM                   VARCHAR2(80 CHAR)  
SPEC_FORMULA_VERSION_NUM          NUMBER(10)         
DR_SENSITIVITY_NUM                NUMBER(38)         
PA_SPEC_RISKTODR_CD               CHAR(4 CHAR)       
PA_SPEC_VALUE_NUM_TEMP            VARCHAR2(40 CHAR)  

I ran the same script on a small test table I created with fake numbers, and it ran successfully. Perhaps this suggests that this is a data issue? Regardless, I don't know how else I can tackle his. Any suggestions will be greatly appreciated.

Community
  • 1
  • 1
Tamara Aviv
  • 885
  • 1
  • 11
  • 28
  • null values ? to_char(nvl(PA_SPEC_VALUE_NUM,0)) – Gar May 31 '16 at 16:14
  • I do not think a NUMBER(38,0) could contain spaces ... unless the database is somehow corrupt – Gar May 31 '16 at 16:20
  • Can you edit the question to add the table structure (e.g. `DESCRIBE TPA_SPEC_COPY`), some sample data, and just for fun your session's `NLS_NUMERIC_CHARACTERS` setting? Incidentally, storing numbers as strings is a really bad idea; why are you making this change? – Alex Poole May 31 '16 at 16:45
  • 1
    @Nicarus - that's how SQL Developer shows the ORA-01722 error, it is not showing the value it errored on. It would be nice if it did that, but it doesn't. And @Gar you can pass null to `to_char()`, you just get null back. – Alex Poole May 31 '16 at 16:47
  • @Gar I tested the script on my side test table, which contains null values in the column, and it ran successfully. So null might not be the issue. – Tamara Aviv May 31 '16 at 16:52
  • 1
    It i[s possible](http://stackoverflow.com/q/14273113/266304) to have [corrupt numeric data](http://stackoverflow.com/q/20004679/266304), but I would have thought the CTAS would have failed first. – Alex Poole May 31 '16 at 16:54
  • @AlexPoole, I agree with you regarding storing numbers as strings. However, there's a need to be able to occasionally store a few allowed strings in this column, e.g. NA, which is a different case from having a null there. Could you suggest another way to address this? p.s. I'm working on getting the info you asked for. – Tamara Aviv May 31 '16 at 17:04
  • 1
    You could use magic numbers but they have their own issues. Or a separate column as a flag maybe - for NA, `applicable` with Y/N perhaps; or a string column for non-numeric values and only allow one column at a time to be set. Keep storing the numbers as numbers though, to save pain later. – Alex Poole May 31 '16 at 17:11
  • Try: `Select * from TPA_SPEC where LENGTH(TRIM(TRANSLATE(TO_CHAR(PA_SPEC_VALUE_NUM), ' +-.0123456789', ' ')))>0` this may identify which rows the system is having trouble translating. To narrow down where to focus your attention (or exclude those records when inserting to see if that truly identifies the problem) – xQbert May 31 '16 at 17:15
  • @xQbert, Thanks. I tried running your query, but I'm getting the same error as before: ORA-01722: invalid number 01722. 00000 - "invalid number" *Cause: The specified number was invalid. *Action: Specify a valid number. – Tamara Aviv May 31 '16 at 19:56
  • @AlexPoole I think I will follow your suggestion to have a designated flag column for the special circumstances. Thank you. It would still be nice to figure out what's causing this error. – Tamara Aviv May 31 '16 at 19:57
  • Yes, you still seem to have corrupt data. Do you get the same error running that query against the original table? – Alex Poole May 31 '16 at 20:50
  • I've no idea how a database would allow `01722. 00000` to be stored in a numeric field as '2. 0' is invalid. can you explicitly exclude this record and try? – xQbert May 31 '16 at 21:12
  • @xQbert - that isn't the stored value; that's how SQL Developer displays the ORA-01722 error. – Alex Poole May 31 '16 at 21:54

1 Answers1

2

I can only suspect some kind of data corruption, I'd suggest this plsql code to try find it, adding a commit after the update would help at least moving the good values.

I know this is not the best way to do it, it is code that is gonna be used once.

begin
  for i in (select pa_id,PA_SPEC_VALUE_NUM from TPA_SPEC_COPY)
loop
   begin
    update TPA_SPEC_COPY set PA_SPEC_VALUE_NUM_TEMP=to_char(PA_SPEC_VALUE_NUM)

     where pa_id=i.pa_id;
   exception when others
    then 
       dbms_output.put_line('Problem with ' || i.pa_id);
 end;
end loop;
end;
Gar
  • 852
  • 13
  • 20