how to get the length of the string in sqlcl - oracle

i am trying to display the top three rows based on their length of the string in names.but the system just reads the predefined length of the string column not the string in the column
SQL> select max(length(name)) from cus_detail;
MAX(LENGTH(NAME))
-----------------
10
SQL> select *
from (select id, name, length(name) as namelen, distance
from cus_detail
order by length(name) desc
)
where rownum<=3;
ID NAME NAMELEN DISTANCE
---------- ---------- ---------- ----------
1 paul 10 15
2 baul 10 15
3 mereum 10 20

That's what CHAR datatype does - it right-pads value with spaces up to the full column length:
SQL> create table test (name char(10));
Table created.
SQL> insert into test (name) values ('London');
1 row created.
SQL> select max(length(name)) from test;
MAX(LENGTH(NAME))
-----------------
10
SQL>
A closer look:
SQL> select '#' || name ||'#' name, dump(name) dmp from test;
NAME DMP
------------ --------------------------------------------------
#London # Typ=96 Len=10: 76,111,110,100,111,110,32,32,32,32
^^^^ L o n d o n ^^^^^^^^^^^
spaces spaces
So, you could trim the value:
SQL> select max(length(trim(name))) from test;
MAX(LENGTH(TRIM(NAME)))
-----------------------
6
SQL>
or - even better - change column's datatype to varchar2.

Related

Why is my SQL table result in two lines? check the screenshot below

After creating and inserting values into my table, when I look out for the results, I get it in two lines. I don't know what to do. please help.SQL search result
To illustrate what you were already told in a comment.
This is (more or less) what you have:
SQL> create table employee_database
2 (employee_name varchar2(50),
3 street varchar2(30),
4 city varchar2(30));
Table created.
SQL> insert into employee_database values ('abc', 'bgefdc street', 'chennai');
1 row created.
SQL> select * from employee_database;
EMPLOYEE_NAME
--------------------------------------------------
STREET CITY
------------------------------ ------------------------------
abc
bgefdc street chennai
If you format columns (basically, shorten columns as they are too long for the current line size):
SQL> col employee_name format a20
SQL> col street format a20
SQL> col city format a20
SQL>
SQL> select * from employee_database;
EMPLOYEE_NAME STREET CITY
-------------------- -------------------- --------------------
abc bgefdc street chennai
SQL>
Alternatively, enlarge line size (I'll first revert columns' formatting):
SQL> col employee_name format a50
SQL> col street format a30
SQL> col city format a30
SQL> select * from employee_database;
EMPLOYEE_NAME
--------------------------------------------------
STREET CITY
------------------------------ ------------------------------
abc
bgefdc street chennai
SQL> set linesize 200
SQL> select * from employee_database;
EMPLOYEE_NAME STREET CITY
-------------------------------------------------- ------------------------------ ------------------------------
abc bgefdc street chennai
SQL>

Getting data from different tables between dates when each table has it on date modified

Like to get some views from you all, regarding one scenario i'm struggling with currently. Below is a problem statement
I have Table A , B , C
A has below column
user|modified date| wokred_on A | ..some more related to user operation
B has columns
user | modified date | worked on B | ..some other columns
C has columsn
user | modified date | worked on C| ..some other columns
these tables are not have any direct relation except then user.
we have to pull data from these tables for a user between given dates with the count op action or work he has done between a given date range?
my struggle here is these each table has it's own date modified if a date range selected which is not in other column but still i need to pull the data as user has worked on it in between dates.
can it be possible to select these dates and have the in one column so that one can put that in where clause and having outer joins to pull other records ?
Sorry for this big problem statement. any suggestions are very much appreciated
Below is a use case.just extending the assumption given by littlefoot
First, test case:
SQL> create table a (cuser varchar2(10), modified_date date,action );
varchar2 (10) )
Table created.
SQL> create table b (
Table created.cuser varchar2(10), modified_date date,action
varchar2 (10) );
SQL> create table c (cuser varchar2(10), modified_date date,action
varchar2 (10) ));
Table created.
SQL> insert into a values ('lf', date '2018-05-01', 'issue raised');
1 row created.
SQL> insert into a values ('mc', date '2018-05-01', 'issue raised ');
1 row created.
SQL> insert into b values ('lf', date '2018-05-01',issue raised');
1 row created.
SQL> insert into b values ('lf', date '2018-05-01','issue resolved');
1 row created.
SQL> insert into c values ('if', date '2018-05-28',' issue resolved');
1 row created.
SQL> insert into c values ('mc', date '2018-05-13','issue raised');
1 row created.
SQL> insert into c values ('mc', date '2018-05-13','issue resolved');
1 row created.
SQL> alter session set nls_date_format = 'yyyy-mm-dd';
Session altered.
SQL> select * from a;
CUSER MODIFIED_D. ACTION
---------- ----------
lf 2018-05-01 issue raised
mc 2018-05-01 issue raised
SQL> select * from b;
CUSER MODIFIED_D ACTION
---------- ----------. ______________
lf 2018-05-01 issue raised
lf 2018-05-01. issue resolve
SQL> select * from c;
CUSER MODIFIED_D. ACTION
---------- ----------
If 2018-05-28. issue resolve
mc 2018-05-13. issue raised
mc 2018-05-13. issue resolve
CUSER DATE CNT_ISSUE_RAISED CNT_ISSUE_RESOLVED
------ ------- --------------- -------------------
if 2018-05-01 2 1
lf 2018-05-28 0 1
mc 2018-05-01 0 1
mc 2018-05-13 1 1
This is how I understood the question.
First, test case:
SQL> create table a (cuser varchar2(10), modified_date date);
Table created.
SQL> create table b (cuser varchar2(10), modified_date date);
Table created.
SQL> create table c (cuser varchar2(10), modified_date date);
Table created.
SQL> insert into a values ('lf', date '2018-05-01');
1 row created.
SQL> insert into a values ('mc', date '2018-05-15');
1 row created.
SQL> insert into b values ('lf', date '2018-05-07');
1 row created.
SQL> insert into b values ('lf', date '2018-05-08');
1 row created.
SQL> insert into c values ('jw', date '2018-05-28');
1 row created.
SQL> insert into c values ('mc', date '2018-05-13');
1 row created.
SQL> insert into c values ('mc', date '2018-05-22');
1 row created.
SQL> alter session set nls_date_format = 'yyyy-mm-dd';
Session altered.
SQL> select * from a;
CUSER MODIFIED_D
---------- ----------
lf 2018-05-01
mc 2018-05-15
SQL> select * from b;
CUSER MODIFIED_D
---------- ----------
lf 2018-05-07
lf 2018-05-08
SQL> select * from c;
CUSER MODIFIED_D
---------- ----------
jw 2018-05-28
mc 2018-05-13
mc 2018-05-22
Query which returns desired result - number of rows per each user in every table, in desired date period. As I use SQL*Plus, variables are preceded by && to avoid multiple insert requests. In a tool you use, that might be a colon (:).
SQL> select nvl(nvl(a.cuser, b.cuser), c.cuser) cuser,
2 count(distinct a.modified_date) cnt_a,
3 count(distinct b.modified_date) cnt_b,
4 count(distinct c.modified_date) cnt_c
5 from a full outer join b on a.cuser = b.cuser
6 full outer join c on a.cuser = c.cuser
7 where a.modified_date between &&date_from and &&date_to
8 or b.modified_date between &&date_from and &&date_to
9 or c.modified_date between &&date_from and &&date_to
10 group by nvl(nvl(a.cuser, b.cuser), c.cuser)
11 order by 1;
Enter value for date_from: '2018-05-01'
Enter value for date_to: '2018-06-01'
CUSER CNT_A CNT_B CNT_C
---------- ---------- ---------- ----------
jw 0 0 1
lf 1 2 0
mc 1 0 2
SQL>

Oracle join nextval from sequence

Let's assume
Table TARGET {
ID IDENTITY ...,
...
JOB_NO NUMBER
}
My question is, how can I generate the JOB_NO (by means of a sequence) so that all inserts that have been committed in a statement have the same job_no.
The output should be something like for the n-th execution of that insert stmt.
ID ... JOB_NO
1 ... 123
2 ... 123
3 ... 123
The following is obviously not working. But what is the correct Oracle syntax?
INSERT INTO TARGET SELECT A.*, B.* FROM my_source_table A, (SELECT x.nextval from dual) B
Thanks a lot
Juergen
You could once select the NEXTVAL for every such insert, which increments the sequence and then use CURRVAL within the INSERT.
Let's say this is your sequence
create sequence seq START WITH 123 ;
Always specify the column names in the INSERT to avoid confusion, don't use select * from
select seq.NEXTVAL FROM DUAL;
INSERT INTO TARGET(JOB_NO,col1,col2,..)
SELECT seq.CURRVAL, a.col1,a.col2 FROM my_source_table A, ..
You should be able to do something like:
insert into target select my_seq.nextval, a.* from source a;
Update based on comment below:
SQL*Plus: Release 12.1.0.2.0 Production on Wed Apr 11 12:48:21 2018
Copyright (c) 1982, 2014, Oracle. All rights reserved.
Connected to:
Oracle Database 12c Standard Edition Release 12.1.0.2.0 - 64bit Production
With the Automatic Storage Management option
SQL> create table a(id number, name varchar2(10));
Table created.
SQL> insert into a values(1,'Larry');
1 row created.
SQL> c/1/2
1* insert into a values(2,'Larry')
SQL> c/Larry/Moe
1* insert into a values(2,'Moe')
SQL> /
1 row created.
SQL> c/2/3
1* insert into a values(3,'Moe')
SQL> c/Moe/Curly
1* insert into a values(3,'Curly')
SQL> /
1 row created.
SQL> commit;
Commit complete.
SQL> select * from a;
ID NAME
---------- ----------
1 Larry
2 Moe
3 Curly
SQL> create table b as select 1 id, a.id id_a, a.name from a where 1=0;
Table created.
SQL> desc b
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NUMBER
ID_A NUMBER
NAME VARCHAR2(10)
SQL> create sequence seq_a;
Sequence created.
SQL> insert into b select seq_a.nextval, a.* from a;
3 rows created.
SQL> select * from b;
ID ID_A NAME
---------- ---------- ----------
1 1 Larry
2 2 Moe
3 3 Curly

Concatenating numbers in virtual column expression throws ORA-12899: value too large for column

While I gave this answer to a question yesterday, I suggested to use a VIRTUAL COLUMN for computed values instead of manually updating it.
I did a test myself, and figured out an issue with the data size that the virtual column expression takes while concatenating two NUMBER type columns. Though, no issue while concatenating two characters.
DB version :
SQL> select banner from v$version where rownum = 1;
BANNER
--------------------------------------------------------------------------------
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
SQL>
Test case 1 : Concatenating strings
SQL> CREATE TABLE t(
2 ID varchar2(2),
3 num varchar2(2),
4 text VARCHAR2(10) generated always as (id||'_'||num) VIRTUAL
5 );
Table created.
SQL>
SQL> INSERT INTO t(ID, num) VALUES ('a', 'e');
1 row created.
SQL> INSERT INTO t(ID, num) VALUES ('b', 'f');
1 row created.
SQL> INSERT INTO t(ID, num) VALUES ('c', 'g');
1 row created.
SQL>
SQL> SELECT * FROM T;
ID NU TEXT
-- -- ----------
a e a_e
b f b_f
c g c_g
SQL>
So, no issues with concatenating two character type columns.
Test case 2 : concatenating numbers
SQL> CREATE TABLE t(
2 ID NUMBER,
3 num NUMBER,
4 text VARCHAR2(10) generated always as (to_char(id)||'_'||to_char(num)) VIRTUAL
5 );
text VARCHAR2(10) generated always as (to_char(id)||'_'||to_char(num)) VIRTUAL
*
ERROR at line 4:
ORA-12899: value too large for column "TEXT" (actual: 10, maximum: 81)
Not allowed? Huh! Let's increase the size -
SQL> CREATE TABLE t(
2 ID NUMBER,
3 num NUMBER,
4 text VARCHAR2(81) generated always as (to_char(id)||'_'||to_char(num)) VIRTUAL
5 );
Table created.
SQL>
SQL> INSERT INTO t(ID, num) VALUES (1, 4);
1 row created.
SQL> INSERT INTO t(ID, num) VALUES (2, 5);
1 row created.
SQL> INSERT INTO t(ID, num) VALUES (3, 6);
1 row created.
SQL>
SQL> SELECT * FROM T;
ID NUM
---------- ----------
TEXT
--------------------------------------------------------------------------------
1 4
1_4
2 5
2_5
3 6
3_6
SQL> set linesize 200
SQL> SELECT * FROM T;
ID NUM TEXT
---------- ---------- ----------------------------------------------------------------------------------------------------
1 4 1_4
2 5 2_5
3 6 3_6
SQL>
So what happened now? Table got created, but why VIRTUAL COLUMN occupies that much size when the expected data size is just 3 bytes, however it takes 81 bytes.
Checking the length, value is correct, however, the data size is much larger. For example, I expect the length to be 3, so I declare the size of the column as 10 bytes. But the virtual column expression yields the value with a size much more than that.
SQL> CREATE TABLE t(
2 ID NUMBER,
3 num NUMBER,
4 text VARCHAR2(10) generated always as (length(to_char(id)||'_'||to_char(num))) VIRTUAL
5 );
text VARCHAR2(10) generated always as (length(to_char(id)||'_'||to_char(num))) VIRTUAL
*
ERROR at line 4:
ORA-12899: value too large for column "TEXT" (actual: 10, maximum: 40)
SQL>
SQL> CREATE TABLE t(
2 ID NUMBER,
3 num NUMBER,
4 text VARCHAR2(81) generated always as (length(to_char(id)||'_'||to_char(num))) VIRTUAL
5 );
Table created.
SQL>
SQL> INSERT INTO t(ID, num) VALUES (1, 4);
1 row created.
SQL> INSERT INTO t(ID, num) VALUES (2, 5);
1 row created.
SQL> INSERT INTO t(ID, num) VALUES (3, 6);
1 row created.
SQL>
SQL> SELECT * FROM T;
ID NUM TEXT
---------- ---------- ----------------------------------------------------------------------------------------------------
1 4 3
2 5 3
3 6 3
SQL> clear columns
columns cleared
SQL> SELECT * FROM T;
ID NUM TEXT
---------- ---------- ---------------------------------------------------------------------------------
1 4 3
2 5 3
3 6 3
Any insight is more than welcome.
UDPATE Thanks to Alex Poole. I did not think about the implicit conversion, so I did not care to CAST the expression explicitly. So, the below works -
SQL> DROP TABLE t PURGE;
Table dropped.
SQL>
SQL> CREATE TABLE t(
2 ID NUMBER,
3 num NUMBER,
4 text VARCHAR2(10) generated always as (cast(to_char(id)||'_'||to_char(num) as varchar2(3))) VIRTUAL
5 );
Table created.
SQL>
SQL> INSERT INTO t(ID, num) VALUES (1, 4);
1 row created.
SQL> INSERT INTO t(ID, num) VALUES (2, 5);
1 row created.
SQL> INSERT INTO t(ID, num) VALUES (3, 6);
1 row created.
SQL>
SQL> SELECT * FROM T;
ID NUM TEXT
---------- ---------- ----------
1 4 1_4
2 5 2_5
3 6 3_6
SQL>
Your numbers are not constrained. With single digit (positive) numbers you know the concatendated length can only be three, but the virtual column has to be large enough for any number - so it looks like it's allowing up to 40 digits for the implicit format model (38 significant digits, the decimal separator, and the sign; #collspar's lexicalisation).
Having said that, constraining the number column wouldn't be reflected in the virtual column length - making both columns NUMBER(1,0) still leaves the concatenation requiring 81 characters. Taking the substring of the generated value won't work either, in this case getting ORA-12899: value too large for column "TEXT" (actual: 10, maximum: 40). Supplying a format model for each to_char() call, e.g. of FM999), would work but restricts the values either side of the underscore rather than the overall length directly.
If you want to restrict the column size, you can cast it to the same data type and size, which is more explicit:
text VARCHAR2(10) generated always as
(cast(to_char(id)||'_'||to_char(num) as VARCHAR2(10))) VIRTUAL

How to prettify the output coming from the SELECT query in command prompt?

I ran the simple select query in the command prompt,but the output rows are not coming in a single line. See below:
SQL> set pagesize 2000
SQL> select * from xtern_empl_rpt ;
EMP LAST_NAME
--- --------------------------------------------------
FIRST_NAME SSN
-------------------------------------------------- ---------
EMAIL_ADDR
--------------------------------------------------------------------------------
YEARS_OF_SERVICE
----------------
001 Hutt
Jabba 896743856
jabba#thecompany.com
18
002 Simpson
Homer 382947382
homer#thecompany.com
20
003 Kent
Clark 082736194
superman#thecompany.com
5
004 Kid
Billy 928743627
billythkid#thecompany.com
9
005 Stranger
Perfect 389209831
nobody#thecompany.com
23
006 Zoidberg
Dr 094510283
crustacean#thecompany.com
1
6 rows selected.
SQL>
Could you please help me to make each rows in a single line?
Edit
I tried below,but still is not prettified.
SQL> SET LINESIZE 4000
SQL> select * from xtern_empl_rpt ;
EMP LAST_NAME FIRST_NAME
SSN EMAIL_ADDR
YEARS_OF_SERVICE
--- -------------------------------------------------- -------------------------
------------------------- --------- --------------------------------------------
-------------------------------------------------------- ----------------
001 Hutt Jabba
896743856 jabba#thecompany.com
18
002 Simpson Homer
382947382 homer#thecompany.com
20
003 Kent Clark
082736194 superman#thecompany.com
5
004 Kid Billy
928743627 billythkid#thecompany.com
9
005 Stranger Perfect
389209831 nobody#thecompany.com
23
006 Zoidberg Dr
094510283 crustacean#thecompany.com
1
6 rows selected.
SQL>
set your column widths to fit in the screen
eg:
column EMAIL_ADDR format a30
where a is hte column width. you can use WRA to wrap the column
eg
column EMAIL_ADDR format a30 WRA
or TRU to truncate, WOR to break on word boundaries
for example:
SQL> select * from emp;
ID FIRST_NAME
---------- ------------------------------
LAST_NAME
------------------------------
EMAIL_ADDR
--------------------------------------------------
1 Dazza
Smith
d_dazzal#dazzal.com
so the output is a bit tricky to read as email_addr was padded to 300 characters (as my table had it defined as varchar2(300) which sql*plus uses to format the output).
first set an appropriate linesize:
SQL> set linesize 100
now lets set the columns so they fit on one line (linesize should be greater than the total col widths):
SQL> column email_addr format a30
SQL> column last_name format a20
SQL> column first_name format a20
SQL> select * from emp;
ID FIRST_NAME LAST_NAME EMAIL_ADDR
---------- -------------------- -------------------- ------------------------------
1 Dazza Smith d_dazzal#dazzal.com
so now the columns fit easily onto a reasonably sized terminal.
in your case first_name and last_name are varchar2(50)'s yet the data in them is much smaller, so i'd start with column first_name format a15 (same for last_name). with email, your column is varchar2(100) yet the max sized output was 25 chars, so put column email format a25 for a starter.
if you did that, you should get output (if linesize is high enough) like:
SQL> select * from xtern_empl_rpt ;
EMP LAST_NAME FIRST_NAME SSN EMAIL_ADDR YEARS_OF_SERVICE
--- --------------- -------------- --------- ------------------------- ----------------
001 Hutt Jabba 896743856 jabba#thecompany.com 18
finally as requested. WRA TRU and WOR. WRA is default by the way, so you dont have to use it but lets say we had:
SQL> select * from test;
A
--------------------------------------
THIS IS A SIMPLE WRAPPING TEST
but i wanted to format this as 10 characters width:
S
QL> col a format a10 WRA
SQL> select * from test;
A
----------
THIS IS A
SIMPLE WRA
PPING TEST
the WRA means just chop the string at 10 chars, regardless of whether we are in the middle of a word or not. if we wanted to break ONLY on word endings (where possible as a word > 10 still needs to break):
SQL> col a format a10 WOR
SQL> select * from test;
A
----------
THIS IS A
SIMPLE
WRAPPING
TEST
now the output is broken at word boundaries and not necessarily at 10 chars.
if we only wanted the first 10 chars and no line wrapping, we could use TRU:
SQL> col a format a10 TRU
SQL> select * from test;
A
----------
THIS IS A
This should fix your issue:
set wrap off
Try something like:
SET LINESIZE 120
(Adjust 120 to required maximum width.)
Before execute the select query, execute the following query to get the select query's output in CSV format. Then the output will be shown in CSV format.
set markup csv on;

Resources