incerement the values in Oracle insert statement (neagative numbers) - oracle

I have to insert data in a table. It has a colum whose values should negative numbers like -1,-2,-3..... so on upto -50.
I thought of using sequence but it wont accept the negative values.
How can i genarate i mean insert the values???

"I thought of using sequence but it wont accept the negative values."
Are you sure?
SQL> create table t1 (c1 number)
2 /
Table created.
SQL> create sequence myseq increment by -1
2 /
Sequence created.
SQL> insert into t1 values (myseq.nextval)
2 /
1 row created.
SQL> r
1* insert into t1 values (myseq.nextval)
1 row created.
SQL> r
1* insert into t1 values (myseq.nextval)
1 row created.
SQL> select * from t1
2 /
C1
----------
-1
-2
-3
SQL>
What version of the database are you using? This is from Oracle 11g R1, but I don't think it's a recent feature.

search for any table with minium recourd count you like, and then write:
use a select to generate the data:
select (rownum * -1) as negRowNum from whatevertableyoufound where rownum <= 50

Use 0 - rownum.
SELECT 0 - rownum
FROM DUAL
CONNECT BY LEVEL <= 50;
0-ROWNUM
-1
-2
-3
-4
-5
...

Related

Order and filter follow different criteria in Oracle?

I'm having a problem while trying to apply a filter in an Oracle (12.2.0.1.0) query.
When I query for the values of a column in a table using order by that same column, I get
75A0000000
7597953181
7597953182
But then, when I try to filter the rows with the column between the first and the last value I'm not getting results at all.
This works perfectly fine if the column has only numeric values, but it gets it all wrong when there is some alphabetic value in the middle.
It seems like Oracle is following the criteria A<0 when ordering a result but A>0 when filtering that result.
This can be reproduced using this query:
select * from (
WITH DATA AS
(SELECT '1, A, 2' str FROM dual)
SELECT trim(regexp_substr(str, '[^,]+', 1, LEVEL)) str
FROM DATA
CONNECT BY instr(str, ',', 1, LEVEL - 1) > 0)
where str>='1' and str<='A'
order by str
The result of this query is
A
1
2
that should mean A is less than 1, but the filter applied to make it return some values is just the opposite : str values greater or equal than 1 and less or equal than A.
Anybody knows why? Thanks in advance.
To me, it looks as if it is about binary or linguistic sort.
Sample data:
SQL> select * from test;
C
-
1
A
2
Sort by col, as is:
SQL> select col, ascii(col)
2 from test
3 order by col;
C ASCII(COL)
- ----------
A 65
1 49
2 50
Or, sort by col's ASCII code:
SQL> select col, ascii(col)
2 from test
3 order by ascii(col);
C ASCII(COL)
- ----------
1 49
2 50
A 65
Explicitly stating binary or linguistic sort:
SQL> select col
2 from test
3 order by nlssort(col, 'nls_sort=binary'); --> binary
C
-
1
2
A
SQL> select col
2 from test
3 order by nlssort(col, 'nls_sort=croatian'); --> linguistic
C
-
A
1
2
SQL>
Or, alter session and set nls_sort you want:
SQL> alter session set nls_sort='binary';
Session altered.
SQL> select * From test order by col;
C
-
1
2
A
SQL>
If you get unexpected result, check what's nls_sort set in your session:
SQL> select * from nls_session_parameters where parameter = 'NLS_SORT';
PARAMETER VALUE
------------------------------ ----------------------------------------
NLS_SORT BINARY
SQL>
Using your query:
SQL> select * from (
2 WITH DATA AS
3 (SELECT '1, A, 2' str FROM dual)
4 SELECT trim(regexp_substr(str, '[^,]+', 1, LEVEL)) str
5 FROM DATA
6 CONNECT BY instr(str, ',', 1, LEVEL - 1) > 0)
7 where str>='1' and str<='A'
8 order by nlssort(str, 'nls_sort=binary'); --> this
STR
-------
1
2
A
SQL>

How to select partition name of specific data?

I want to select a data and wanna see in which partition.
partition column is : code (varchar column)
Select .... -- I want to find partition name
from
partition_table
where to_number(code) = 55;
why I need to this:
I have a data which code is '55' but in that table when I use partition column I do not select it. But there is data which value is '55'
So I want to that data in which partition.
And the data is not in PDEFAULT partition. I ve already check it.
edit
data is in another partition. I think there is a problem with exchange partition process
thanks in advance
There are a couple of ways.
1) The rowid will point to the partition object
SQL> create table t ( x int, y int )
2 partition by range (x )
3 ( partition p1 values less than ( 100 ),
4 partition p2 values less than ( 200 )
5 );
Table created.
SQL>
SQL> insert into t values (34,34);
1 row created.
SQL>
SQL> select rowid from t;
ROWID
------------------
AAA0cqAAHAAAAQ6AAA
1 row selected.
SQL>
SQL> select dbms_rowid.rowid_object(rowid) from t;
DBMS_ROWID.ROWID_OBJECT(ROWID)
------------------------------
214826
1 row selected.
SQL>
SQL> select subobject_name
2 from user_objects
3 where data_Object_id =
4 ( select dbms_rowid.rowid_object(rowid) from t );
SUBOBJECT_NAME
------------------------------------------------------------
P1
2) You can data mine the dictionary to probe the HIGH_VALUE column in USER_TAB_PARTITIONS. I did a video on how to do that here
https://www.youtube.com/watch?v=yKHQQXKdfOM

Max function in Oracle 12

I have two records below. I was trying to pull the latest record based from the Sold_DT, which would give me the record with 7 in Item column.
Store Sold_DT Item
CVS 1/22/2017 12:05:00 AM 5
CVS_S_Eleven 1/22/2017 10:41:00 AM 7
Here is my attempted query in Oracle:
select
store,
max(sold_dt) as max_dt,
item
from temp
group by store, item
Would someone please point me to the correct direction so that I can return only the latest Sold_DT? which is only this:
Store Sold_DT Item
CVS_S_Eleven 1/22/2017 10:41:00 AM 7
Try the MIN/MAX with KEEP. As mathguy points out, if you have two stores tied for most recent, it will get tricky and you are best to add a tiebreaker if you want a single consistent record, or use another technique if you want all ties.
select
max(store) keep (DENSE_RANK FIRST ORDER BY sold_dt desc) max_store,
max(sold_dt) as max_dt,
max(item) keep (DENSE_RANK FIRST ORDER BY sold_dt desc) max_item
from temp
You can take max of sold date from subquery like below and join with main table on that date value
select t1.* from
from temp t1 join (select
max(sold_dt) as max_dt, item
from temp) t2 on t1.Max_dt=t2sold_dt
I wasn't sure if you only wanted one row if there are two with the same date and time. I assumed that you only want one. Of course, in this case there is only one row with max date anyway.
SQL>
SQL> drop table temp;
Table dropped.
SQL>
SQL> create table temp
2 (
3 Store varchar2(12),
4 Sold_DT date,
5 Item number
6 );
Table created.
SQL>
SQL> insert into temp values ('CVS',to_date('01/22/2017 12:05:00 AM','MM/DD/YYYY HH:MI:SS AM'),5);
1 row created.
SQL> insert into temp values ('CVS_S_Eleven',to_date('01/22/2017 10:41:00 AM','MM/DD/YYYY HH:MI:SS AM'),7);
1 row created.
SQL>
SQL> commit;
Commit complete.
SQL>
SQL> select
2 store,
3 Sold_DT,
4 item
5 from temp
6 where
7 Sold_DT = (select max(Sold_DT) from temp) and
8 rownum < 2;
STORE SOLD_DT ITEM
------------ --------- ----------
CVS_S_Eleven 22-JAN-17 7
SQL>
SQL> spool off

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

insert and select in one query default values

I use following query to insert a new row:
insert into table1 (c1, c2, c3) (select c1, c2, c3 from table2 where some_condition)
This works finely if there is a row in table2 that satisfies some_condition. But if there are no rows, nothing is inserted.
Are there any way to specify default values to insert if select returns empty result set? I want to do that in one sql query.
This isn't very pretty, but it does what you want, You'd need to test with your environment to see if it performs well enough
SQL> drop table so_tgt;
Table dropped.
SQL>
SQL> create table so_src (
2 c1 varchar2(6)
3 ,c2 varchar2(6)
4 ,c3 varchar2(6)
5 );
Table created.
SQL>
SQL> insert into so_src values ( 'foo','bar','moo' );
1 row created.
SQL>
SQL> create table so_tgt as select * from so_src where 1 = 0;
Table created.
SQL>
SQL> /* Test for existing row insert */
SQL> insert into so_tgt
2 with x as ( select s.*, 1 as r
3 from so_src s
4 where c1='foo'
5 union
6 select 'x','y','z',0 as r /* DEFAULT VALUES */
7 from dual )
8 select c1,c2,c3
9 from x
10 where r = ( select max(r) from x ) ;
1 row created.
SQL>
SQL> select * from so_tgt;
C1 C2 C3
------ ------ ------
foo bar moo
SQL> truncate table so_tgt;
Table truncated.
SQL>
SQL> /* Test for default row insert */
SQL> insert into so_tgt
2 with x as ( select s.*, 1 as r
3 from so_src s
4 where c1='far'
5 union
6 select 'x','y','z',0 as r /* DEFAULT VALUES */
7 from dual )
8 select c1,c2,c3
9 from x
10 where r = ( select max(r) from x ) ;
1 row created.
SQL>
SQL> select * from so_tgt;
C1 C2 C3
------ ------ ------
x y z
SQL> truncate table so_tgt ;
Table truncated.
The quick and dirty way, if you don't mind repeating some_condition and where some_condition doesn't depend on the values in table2 is:
insert into table1 (c1,c2,c3)
select c1, c2, c3 from table2 where some_condition
union select defaultvalue1, defaultvalue2, defaultvalue3 from dual where not (some_condition)
If some_condition does depend on values in table2, then you can do (untested):
insert into table1 (c1,c2,c3)
select nvl(t2.c1, defaultvalue1), nvl(t2.c2, defaultvalue2), nvl(t2.c2, defaultvalue3)
from dual left join (select c1,c2,c3 from table2 where some_condition) t2
on 1 = 1
If I'm right, this query will always return at least one row, but if no rows showed up on the right side, then the t2 values will all be returned as null and so the nvl can be used to provide your default values.
Edit: Small caveat. This assumes that the values returned from table2 will not be null or that if they are, you want the default values.

Resources