I am trying to exclude the last line of a data file using SQL*Loader, using the WHEN clause, but when it gets to that line it populates both the bad and discard file, and raises an Error 2.
The line to ignore is the last line and starts with "NOL".
After some reading, Error 2 is a warning about the synatx of the CTL file, but cannot find out where it is wrong. Note, if l remove the last line and then run the SAME CTL file, no ERROR is raised, so the issue cannot be the synatx of the CTL file.
To resolve the issue, l am removing the last line BEFORE loading the data, but would like to find out what the issue is for any future use of the WHEN clause.
I have tried:
file_dt != 'NOL'
(1:1) != 'N'
. . .
But l get the same Error 2.
Has anybody else come across this issue? Or have something that l can try?
Oracle Docs
SQL*Loader Command-Line Reference
For UNIX, the exit codes are as follows:
EX_SUCC 0
EX_FAIL 1
EX_WARN 2
EX_FTL 3
Data:
File-Date,Number
2021-05-04,24
2021-05-04,24
2021-05-04,24
2021-05-04,24
NOL: 4
CTL File:
OPTIONS (READSIZE=51200001, BINDSIZE=51200000, ROWS=5000, ERRORS=0, SKIP=1)
load data
append
into table SOME_SCHEMA.SOME_TABLE
WHEN (01) 'NOL'
fields terminated by ';'
OPTIONALLY ENCLOSED BY '"' AND '"'
trailing nullcols
(
file_dt DATE "YYYY-MM-DD",
a_number
)
Result:
Path used: Conventional
Commit point reached - logical record count 5
Table SOME_SCHEMA.SOME_TABLE:
4 Rows successfully loaded.
Check the log file:
loading-file.log
for more information about the load.
2021-05-06 09:42:12: Finished Loading Data into Table
2021-05-06 09:42:12: Status: 2
I'm not on Unix. Nonetheless, loading should work the same.
Table:
SQL> desc test
Name Null? Type
----------------------------------------------------- -------- --------------------------
FILE_DT DATE
A_NUMBER NUMBER
SQL>
Control file (I included sample data into it, for simplicity):
OPTIONS (READSIZE=51200001, BINDSIZE=51200000, ROWS=5000, ERRORS=0, SKIP=1)
load data
infile *
replace
into table test
WHEN (01) <> 'NOL'
fields terminated by ','
trailing nullcols
(
file_dt DATE "YYYY-MM-DD",
a_number
)
begindata
File-Date,Number
2021-05-04,24
2021-05-04,24
2021-05-04,24
2021-05-04,24
NOL: 4
Loading session and result:
SQL> $sqlldr scott/tiger#orcl control=test38.ctl log=test38.log
SQL*Loader: Release 11.2.0.1.0 - Production on ╚et Svi 6 11:38:00 2021
Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
Commit point reached - logical record count 4
SQL> select * from test;
FILE_DT A_NUMBER
------------------- ----------
04.05.2021 00:00:00 24
04.05.2021 00:00:00 24
04.05.2021 00:00:00 24
04.05.2021 00:00:00 24
Seems to be OK.
So, what did I do differently?
modified WHEN clause
fields are terminated by comma, not semi-colon
removed superfluous information
Related
I can successfully do this:
sql my_connection_string #script1.sql
However, I am struggling to make this work, using a script hosted in a private repo.
sql my_connection_string https://my_private_repo_url/script1.sql
How can I make this work in a single line?
You've got it.
sql user/password#server:ip/service #https://internet.com/script.sql
Here's a public SQL file, courtesy Kris.
c:\sqlcl\22.4\sqlcl\bin>sql hr/oracle#localhost:1523/orclpdb1 #https://gist.githubusercontent.com/krisrice/68e23a2101fe10c8efc26371b8c59d5c/raw/e5a2512d4f74dc79d37e4328e36b81fba15d36a3/dbms_cloud_metric_sql_pkg.sql
SQLcl: Release 22.4 Production on Mon Feb 13 08:18:39 2023
Copyright (c) 1982, 2023, Oracle. All rights reserved.
Last Successful login time: Mon Feb 13 2023 08:18:20 -05:00
Connected to:
Oracle Database 23c Enterprise Edition Release 23.0.0.0.0 - Beta
Version 23.1.0.0.0
login.sql found in the CWD. DB access is restricted for login.sql.
Adjust the SQLPATH to include the path to enable full functionality.
Package OCI_METRICS compiled
Package Body OCI_METRICS compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
0/0 PL/SQL: Compilation unit analysis terminated
12/10 PLS-00201: identifier 'DBMS_CLOUD_TYPES.RESP' must be declared
Errors: check compiler log
Error starting at line : 149 File # https://gist.githubusercontent.com/krisrice/68e23a2101fe10c8efc26371b8c59d5c/raw/e5a2512d4f74dc79d37e4328e36b81fba15d36a3/dbms_cloud_metric_sql_pkg.sql
In command -
begin
oci_metrics.setup('OCI$RESOURCE_PRINCIPAL', 'us-phoenix-1');
for r in ( /* MAIN QUERY for metrics Should only need to adjust this section to adhere to this structure
Expected Columns:
NAMESPACE - The namespace of the metric : 'my_namespace'
COMPARTMENT_ID - The OCID of the compartment to post the metric : 'ocid1.compartment....'
RESOURCE_GROUP - The resource group of the metric : 'my_resource_group'
NAME - The name of the metric : 'my_metric_name'
DIMENSIONS - The dimensions of the metric in json format : '{"factioid":"this","other":"else"}'
VALUE - The numberic value of the metric : 123.45
*/
select 'a_namespace' namespace,
'ocid1.compartment.oc1..aaaaaaaacw2ft7eu33tlaoppsu6mck7qn2wsqefuixcjhza6xhhsbnhvjorq' compartment_id,
'sample_resource_group' resource_group,
'A_SAMPLE_METRIC' name,
'{"machine":"'|| machine ||'","username":"' ||username ||'"}' dimensions,
count(1) value
from v$session
group by username,machine
/* END MAIN QUERY for metrics */
) loop
oci_metrics.addMetric(r.namespace, r.compartment_id, r.resource_group, r.name, r.dimensions, r.value, systimestamp);
end loop;
-- send any remaining metrics
oci_metrics.sendBatch;
end;
Error report -
ORA-04063: package body "HR.OCI_METRICS" has errors
ORA-06508: PL/SQL: could not find program unit being called: "HR.OCI_METRICS"
ORA-06512: at line 2
04063. 00000 - "%s has errors"
*Cause: Attempt to execute a stored procedure or use a view that has
errors. For stored procedures, the problem could be syntax errors
or references to other, non-existent procedures. For views,
the problem could be a reference in the view's defining query to
a non-existent table.
Can also be a table which has references to non-existent or
inaccessible types.
*Action: Fix the errors and/or create referenced objects as necessary.
SQL>
1:0 ¦ HR ¦ localhost:1523/orclpdb1 ¦ viins ¦ None ¦ 00:00:00.347
p_comments => 'see if we can say Hello!',
p_source =>
'select ''Aloha!'' HI_GREETING from dual'
);
COMMIT;
END;
SQL>
I have a ctl file for inserting data to oracle from a txt file. The code is:
OPTIONS (SKIP=1)
LOAD DATA
APPEND
INTO TABLE TIME_TRACK_MY_TRAN
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
TRAILING NULLCOLS
(
VC_EMP_ID,
VC_NAME,
NU_ENTERED_FROM,
DT_DATE,
NU_FLAG,
DT_REAL_DATE "TO_DATE(SUBSTR(TO_CHAR(:DT_REAL_DATE), 0, 9), 'dd/mm/yyyy')",
DT_DATE_TIME "to_char(to_date(:'DT_DATE_TIME','yyyy-mm-dd hh24:mi:ss'),'HH24miss')",
CH_IN_OUT_STATUS,
SR_NO "time_track_my_tran_seq.nextval",
date_time "TO_DATE(SUBSTR(TO_CHAR(:DT_REAL_DATE), 0, 9), 'dd/mm/yyyy')"
The code works well for short dates like 1/9/2020 and 2/3/2020 However I discovered that for longer dates like 10/10/2020 and 22/10/2020 it misbehaves and inserts the year wrongly like instead of 2020 it inserts 0202. I tried changing the range from 0,9 to 0,10 then 1,10 but it gives me an error that:
SQL*Loader: Release 10.2.0.1.0 - Production on Thu Oct 22 16:31:53 2020
Copyright (c) 1982, 2005, Oracle. All rights reserved.
SQL*Loader-350: Syntax error at line 17.
Expecting "," or ")", found end of file.
Format for sqlloader ctl-file is different to SQL, I think it should be similar to this one:
VC_EMP_ID,
VC_NAME,
NU_ENTERED_FROM,
DT_DATE,
NU_FLAG,
DT_DATE_DATE DATE 'yyyy-mm-dd hh24:mi:ss', # don't split data and time component to different columns
CH_IN_OUT_STATUS,
SR_NO "time_track_my_tran_seq.nextval",
date_time DATE 'dd/mm/yyyy'
I have an Oracle DB on one Windows machine and perform an export of all tables + contents using SQL developer 4.0.2.15. File format is plain text SQL, ANSI ISO-8859-1. The line endings are done in UNIX style (1 byte).
The table / column definitions are like:
"PRODUCTNAME" VARCHAR2(120 BYTE),
When I execute this .sql file on the target Windows machine, tables are created and inserts are done. But some items that have exactly 120 bytes in the PRODUCTNAME (including 1 line feed character) fail to insert on the target machine.
I get:
ORA-12899: value too large for column "DBNAME"."TABLENAME"."PRODUCTNAME" (actual: 121, maximum: 120)
I don't understand why. I have no 2-byte characters in this particular string, and the export is definitely done using 0x0A as line break character (checked via Notepad++ status line and its HexView Plugin). I use drag&drop to open the .sql file in the target machine's SQL developer (same version). When I copy the productname with its line break into Notepad++ via clipboard, it count's 120 bytes of length.
I do not understand, why in Oracle developer the script counts this 1 extra character.
I have searched for this in google and found topics here on SO among others, but they don't help me or I don't fully understand them.
What do I miss? Please help!
Create a temporary table (say, TEST) having PRODUCTNAME VARCHAR2(200). Import data into it. Check rows that exceed length of 120 characters.
You might need to use the DUMP function, such as
select dump(productname) from test
It'll show you actual length of data stored in that column. Just for example:
SQL> select ename, dump(ename) dump_e from emp where rownum = 1;
ENAME DUMP_E
---------- ----------------------------------------
KING Typ=1 Len=4: 75,73,78,71
-----
this!
SQL>
[EDIT: TRIM example]
SQL> with test (id, col) as
2 (select 1, 'abc' from dual union
3 select 2, 'def ' from dual union
4 select 3, ' ghi ' from dual
5 )
6 select '#' || col || '#' col,
7 '#' || trim(col) || '#' new_col
8 from test
9 order by id;
COL NEW_COL
-------- --------
#abc# #abc#
#def # #def#
# ghi # #ghi#
SQL>
There's data exported to excel:
MS_ID STARTDATETIME
3 704 285 09.11.2014 11:29:25
3 704 285 09.11.2014 11:29:25
I want to paste it back to Oracle using sqldeveloper table data editor.
For date column I do
alter session set NLS_DATE_FORMAT = 'mm.dd.yyyy HH24:mi:ss';
But I'm also getting:
INSERT INTO "PPB"."CDRGPRS" (MS_ID, STARTDATETIME) VALUES ('3 704 285', TO_DATE('09.11.2014 11:29:25', 'mm.dd.yyyy HH24:mi:ss'))
ORA-01722: invalid number
ORA-06512: at line 1
The SQL above is generated by sqldeveloper.
There's no NLS_NUMBER_FORMAT. How to make Oracle format and parse numbers with spaces as thousand separator?
TO_NUMBER() allows you to specify whatever separators you want using nls_numeric_characters.
SQL> select to_number( '100 123,23'
2 , '999G999G999D99'
3 , 'nls_numeric_characters = '', '''
4 ) as no
5 from dual;
NO
----------
100123.23
G is the number format model corresponding to the separator, which is the second option of your nls_numeric_characters.
If you want to convert it into a number improperly you can REPLACE() the spaces:
SQL> select to_number(replace( '100 12323', ' ')) as no
2 from dual;
NO
--------
10012323
Wrote this macro and put it to Personal.xlsb
Sub nospace()
Application.FindFormat.NumberFormat = "#,##0"
Application.ReplaceFormat.NumberFormat = "0"
Cells.Replace What:="", Replacement:="", _
SearchFormat:=True, ReplaceFormat:=True
End Sub
Question:
Is it possible to have a column name in a select statement changed based on a value in it's result set?
For example, if a year value in a result set is less than 1950, name the column OldYear, otherwise name the column NewYear. The year value in the result set is guaranteed to be the same for all records.
I'm thinking this is impossible, but here was my failed attempt to test the idea:
select 1 as
(case
when 2 = 1 then "name1";
when 1 = 1 then "name2")
from dual;
You can't vary a column name per row of a result set. This is basic to relational databases. The names of columns are part of the table "header" and a name applies to the column under it for all rows.
Re comment: OK, maybe the OP Americus means that the result is known to be exactly one row. But regardless, SQL has no syntax to support a dynamic column alias. Column aliases must be constant in a query.
Even dynamic SQL doesn't help, because you'd have to run the query twice. Once to get the value, and a second time to re-run the query with a different column alias.
The "correct" way to do this in SQL is to have both columns, and have the column that is inappropriate be NULL, such as:
SELECT
CASE WHEN year < 1950 THEN year ELSE NULL END AS OldYear,
CASE WHEN year >= 1950 THEN year ELSE NULL END AS NewYear
FROM some_table_with_years;
There is no good reason to change the column name dynamically - it's analogous to the name of a variable in procedural code - it's just a label that you might refer to later in your code, so you don't want it to change at runtime.
I'm guessing what you're really after is a way to format the output (e.g. for printing in a report) differently depending on the data. In that case I would generate the heading text as a separate column in the query, e.g.:
SELECT 1 AS mydata
,case
when 2 = 1 then 'name1'
when 1 = 1 then 'name2'
end AS myheader
FROM dual;
Then the calling procedure would take the values returned for mydata and myheader and format them for output as required.
You will need something similar to this:
select 'select ' || CASE WHEN YEAR<1950 THEN 'OLDYEAR' ELSE 'NEWYEAR' END || ' FROM TABLE 1' from TABLE_WITH_DATA
This solution requires that you launch SQLPLUS and a .sql file from a .bat file or using some other method with the appropriate Oracle credentials. The .bat file can be kicked off manually, from a server scheduled task, Control-M job, etc...
Output is a .csv file. This also requires that you replace all commas in the output with some other character or risk column/data mismatch in the output.
The trick is that your column headers and data are selected in two different SELECT statements.
It isn't perfect, but it does work, and it's the closest to standard Oracle SQL that I've found for a dynamic column header outside of a development environment. We use this extensively to generate recurring daily/weekly/monthly reports to users without resorting to a GUI. Output is saved to a shared network drive directory/Sharepoint.
REM BEGIN runExtract1.bat file -----------------------------------------
sqlplus username/password#database #C:\DailyExtracts\Extract1.sql > C:\DailyExtracts\Extract1.log
exit
REM END runExtract1.bat file -------------------------------------------
REM BEGIN Extract1.sql file --------------------------------------------
set colsep ,
set pagesize 0
set trimspool on
set linesize 4000
column dt new_val X
select to_char(sysdate,'MON-YYYY') dt from dual;
spool c:\DailyExtracts\&X._Extract1.csv
select '&X-Project_id', 'datacolumn2-Project_Name', 'datacolumn3-Plant_id' from dual;
select
PROJ_ID
||','||
replace(PROJ_NAME,',',';')-- "Project Name"
||','||
PLANT_ID-- "Plant ID"
from PROJECTS
where ADDED_DATE >= TO_DATE('01-'||(select to_char(sysdate,'MON-YYYY') from dual));
spool off
exit
/
REM ------------------------------------------------------------------
CSV OUTPUT (opened in Excel and copy/pasted):
old 1: select '&X-Project_id' 'datacolumn2-Project_Name' 'datacolumn3-Plant_id' from dual
new 1: select 'MAR-2018-Project_id' 'datacolumn2-Project_Name' 'datacolumn3-Plant_id' from dual
MAR-2018-Project_id datacolumn2-Project_Name datacolumn3-Plant_id
31415 name1 1007
31415 name1 2032
32123 name2 3302
32123 name2 3384
32963 name3 2530
33629 name4 1161
34180 name5 1173
34180 name5 1205
...
...
etc...
135 rows selected.