How to create alphanumeric sequence using date and sequence number - sql

I want to create an alphanumeric sequence in oracle. Table name is rel_details it consists of four columns.
rel_id
rel_name
rel_modified_date
rel_desc
In rel_id i want to generate ID like REL230420151001
REL is a string ,
23042015 is today's date,
1001 is a starting number.
How to create this type sequence.

If you are on 12c, then here is one way using IDENTITY column and VIRTUAL column.
Identity column was introduced in version 12c, and virtual column was introduced in version 11g.
SQL> CREATE TABLE t
2 (
3 ID NUMBER GENERATED ALWAYS AS IDENTITY
4 START WITH 1000 INCREMENT BY 1,
5 text VARCHAR2(50),
6 dt DATE DEFAULT SYSDATE,
7 my_text varchar2(1000) GENERATED ALWAYS AS (text||to_char(dt, 'DDMMYYYY')||ID) VIRTUAL
8 );
Table created.
SQL>
SQL> INSERT INTO t(text) VALUES ('REL');
1 row created.
SQL>
SQL> SELECT text, my_text FROM t;
TEXT MY_TEXT
----- ------------------------------
REL REL230420151000
SQL>
I created identity column to start with 1000, you could customize the way you want.
There is one small trick about the VIRTUAL column. You will have to explicitly cast it as varchar2 with fixed size, else the implicit conversion will make it up to maximum size. See this for more details Concatenating numbers in virtual column expression throws ORA-12899: value too large for column

if I were you, I wouldn't bother storing such a sequence in a column; I would store the columns containing the relevant information separately and then either have a virtual column that concatenates them together or do the concatenating in a view.

Check this , you may not able to create seq , but you can use select as below.
create sequence mysec
minvalue 0
start with 10001
increment by 1
nocache;
select 'REL'||to_char(sysdate,'DDMMYYYY')||mysec.nextval from dual;

Related

How can I alter data type and datas in it, numbers separated with comma

I have table , that has field named AMOUNT , amount takes number, table has 1.4m records, i need to upgrade them all . I would like the change NUMBER to varchar and make look like amount datas comma separated , eg: 76543-> 76,543. How can I able to do it?
1 - Create the new column at the end of the table.
2 - Run an update to populate the new table column
(in this step for thousand seperataor look Thousand Seperator function in oracle? )
3 - Drop the old table column
4 - Re-name the new column to the original column name
i need to upgrade them all
Don't; if you have a numeric value then store it as a NUMBER.
I would like the change NUMBER to varchar and make look like amount datas comma separated , eg: 76543-> 76,543. How can I able to do it?
Just change how you are displaying the value rather than changing how you are storing the value.
If you have the table and data:
CREATE TABLE table_name ( amount NUMBER(12,0) );
INSERT INTO table_name ( amount ) VALUES ( 76543 );
If you want to do it in a SELECT statement then use TO_CHAR and include sufficient digits to format the largest number you can hold:
SELECT amount,
TO_CHAR(amount, 'FM999G999G999G990') AS formatted_amount
FROM table_name;
Outputs:
AMOUNT
FORMATTED_AMOUNT
76543
76,543
If you want to do that in the table then add a virtual column:
ALTER TABLE table_name
ADD formatted_amount VARCHAR2(16)
GENERATED ALWAYS AS ( TO_CHAR(amount, 'FM999G999G999G990') );
Then, after adding the virtual column:
SELECT * FROM table_name;
Outputs:
AMOUNT
FORMATTED_AMOUNT
76543
76,543
db<>fiddle here
You can use to_char():
select to_char(col, 'FM999,990;')

Round off float in oracle 11g upto 2 places for all users

I want to insert float value into a column of type float in a table. But value coming from Cobol/Mainframe system after calculation is 5.4999999 but i want to insert 5.50 or 5.49 into oracle table without using round function. So is there any way to set a float value upto 2 decimal places for all the users in oracle 11g or like some setting done by SYSDBA for all the user or Default number value upto 2 or n number of decimal places ? Thanks in advance.
It's impossible to define a constant "format" in which people will always view numbers.
If you can't alter the table due to legacy issues the obvious thing to do would be to create a view on the table in order to transform the data into what you want. You could rename the original table and name the view the same as the original table in order to avoid changing all of your code. Test this first.
rename my_table to my_table_float
create or replace view my_table as
select <some_columns>
, cast(my_float_column as number(36, 2)) as my_float_column
from my_table_float
This solution strikes me as slightly dangerous - you'll need to know exactly what code uses the column and ensure that this code doesn't expect a float. Personally, I'm always more in favour of transforming the data as and when you need it rather than assuming it needs to be in a certain format before it's used.
No, there's no such thing as "setting a float value up to 2 decimal places for all users in Oracle".
You may either alter the target table column to number(*,2) or use the rounding.
You can create your table using a column defined as a number with precision and scale.
create table temp_foo (test number(4,2));
This means that column test will be a maximum of 4 digits in length, with 2 after the decimal place.
Then inserting the following...
insert into temp_foo values(54.345);
And then selecting...
select * from temp_foo;
Will result in a value of 54.35
If you want to allow a bigger number then increase the precision to say 10 and keep the scale at 2 - NUMBER(10,2) - now you can insert 12345678.234535 and you'll get 12345678.23 back out.
In summary, create your table to hold the data in the format your require. Let Oracle do the hard work :)
Hope that helps.
If you can't change the insert code to add a round() call, can't change the value being passed into the insert, and can't change the table structure... then you could use the view replacement Ben suggests; or adjust the data as it's queried directly form the table; or add a trigger to round the value as it is inserted:
create table t42 (id integer, value float);
-- value inserted with more precision than you want
insert into t42 values (1, 5.4999999);
create or replace trigger tr42
before insert or update on t42
for each row
begin
:new.value := round(:new.value, 2);
end;
/
-- value inserted with two decimal places of precision
insert into t42 values (2, 5.4999999);
select * from t42 order by id;
ID VALUE
---------- ----------
1 5.4999999
2 5.5
SQL Fiddle demo. Using a trigger for something like this seems like overkill, but if you've really exhausted all other avenues then it might be something to consider.
If you wanted to get 5.49 when 5.4999999 is inserted then you could use trunc(value, 2) instead:
create or replace trigger tr42
before insert or update on t42
for each row
begin
:new.value := trunc(:new.value, 2);
end;
/
insert into t42 values (3, 5.4999999)
/
select * from t42 order by id;
ID VALUE
---------- ----------
1 5.4999999
2 5.5
3 5.49

Create column from other columns in Database

I have a table name: test
ID | Prefix | ACCID
ID's type is INTEGER which is selected from ID_SEQ
Prefix's type is VARCHAR(6)
ACCID is the combination of Prefix + ID
I want to auto-create ACCID when I insert the ID and Prefix value such as
INSERT INTO TEST (PREFIX) VALUES ('A01407V');
and the database store the ACCID as 'A01407V000001'
I create the sequence as
CREATE SEQUENCE ID_SEQ AS INT MAXVALUE 999999 CYCLE;
How to implement SQL statement to produce this result?
Thank you for all solutions and suggestions.
Ps. I use Apache Derby as my SQL Server
As documented in the manual, Derby supports generated columns (since Version 10.5)
The real problem is the formatting of a number with leading zeros as Derby has no function for that.
If you really, really think you need to store a value that can always be determined by the values already stored in the table, you can use something like this:
create table test
(
id integer,
prefix varchar(6),
accid generated always as (prefix||substr('000000', 1, 6 - length(rtrim(char(id))))||rtrim(char(id)))
);
The expression substr('000000', 1, 6 - length(rtrim(char(id))))||rtrim(char(id)) is just a complicated way to format a the ID with leading zeros.
I would highly recommend to not store this value though. It is much cleaner to create a view that shows this value if you do need access to this in SQL.
You can use COMPUTED Column.
Is a computed column that is based on some other column in the table. We can physically save the data of the column/ or not. Table will automatically update the value of this column.
syntax:
columnname AS expression [PERSISTED]
--PERSISTED will make it physically saved, otherwise it will be calculated every time.
We can create indexes on computed columns.
You add, The following in the table CREATE Script
ACCID AS Prefix + CAST(ID AS CHAR(6)) [PERSISTED]

Flashback versions query

The select statement returns two rows
id || description
1 TWO
2 TWO
I am kind of expecting three rows
id || description
1 ONE
1 TWO
2 TWO
according to the statement from the link which
reads It returns all the committed occurrences of the rows for a query of an object, while NOT displaying the UNCOMMITTED row versions.
The code is as follows :-
CREATE TABLE digits
(id NUMBER(2),
description VARCHAR2(15));
INSERT INTO digits VALUES (1,'ONE');
UPDATE digits SET description ='TWO' WHERE id=1;
INSERT INTO digits VALUES (2,'TWO');
COMMIT;
DELETE FROM digits;
SELECT id,description FROM digits
VERSIONS BETWEEN TIMESTAMP MINVALUE AND MAXVALUE;
The only reason i could think of is that if timestamp minvalue and maxvalue takes the DML timestamp value and not the DDL ones .....please throw some light on this !
The row you think is missing would come from this:
INSERT INTO digits VALUES (1,'ONE');
... but the data is never committed in that state because this:
UPDATE digits SET description ='TWO' WHERE id=1;
... occurred before your COMMIT. So that aligns with the statement you quoted, 1, ONE is not a committed occurrence of the row. There was never any point in time where another session could see those values.
If you look at the version data pseudocolumns you can see that both rows are seen as inserts with their current data:
CREATE TABLE digits (id NUMBER(2), description VARCHAR2(15));
EXEC dbms_lock.sleep(10);
INSERT INTO digits VALUES (1,'ONE');
UPDATE digits SET description ='TWO' WHERE id=1;
INSERT INTO digits VALUES (2,'TWO');
COMMIT;
SELECT id, description, versions_xid, versions_operation
FROM digits
VERSIONS BETWEEN TIMESTAMP MINVALUE AND MAXVALUE;
ID DESCRIPTION VERSIONS_XID V
---------- --------------- ---------------- -
2 TWO 08001B005C0D0100 I
1 TWO 08001B005C0D0100 I
If you commit between the first insert and update you can see the three rows and how they were modified:
CREATE TABLE digits (id NUMBER(2), description VARCHAR2(15));
EXEC dbms_lock.sleep(10);
INSERT INTO digits VALUES (1,'ONE');
COMMIT;
EXEC dbms_lock.sleep(10);
UPDATE digits SET description ='TWO' WHERE id=1;
INSERT INTO digits VALUES (2,'TWO');
COMMIT;
SELECT id, description, versions_xid, versions_operation
FROM digits
VERSIONS BETWEEN TIMESTAMP MINVALUE AND MAXVALUE;
ID DESCRIPTION VERSIONS_XID V
---------- --------------- ---------------- -
2 TWO 060018007C0C0100 I
1 TWO 060018007C0C0100 U
1 ONE 05000B00450C0100 I
I'm not entirely sure why the SLEEP calls are needed, but it doesn't quite work without them (the pseudocolumns are blank and only the current data is shown). I don't think I've ever seen a good explanation of that, but it isn't likely to be an issue in a real-world case.
From the documentation:
Specify BETWEEN TIMESTAMP ... to retrieve the versions of the row that
existed between two timestamps. Both expressions must evaluate to a
timestamp value and cannot evaluate to NULL. MINVALUE and MAXVALUE
resolve to the timestamp of the oldest and most recent data available,
respectively.
Normally MINVALUE would be restricted by the undo retention; since this is a new table it would go back to the point the table was created, which is less than the undo retention. You can't go back beyond that because it wouldn't make any sense: if you tried to use an explicit timestamp value before the table creation time, it would tell you the table structure had changed. The DML/DDL distinction you're making isn't really relevant though, you're only seeing two rows because of when you committed the data.

About dual table structure in Oracle SQL *Plus

We know that "Dual" is a temporary table which exactly contains 1 column whose name is "dummy" which is of "varchar2(1)" type that has 1 single row. The value of that record is "X". The varchar2 has size of 1 which means it should not allow more than a single character.
Now my question is: If it is of varchar2 type, then why it can hold any datatype temporarily AND If we insert characters more than 1 (size), how this is possible for it (dual) to accept it ? Example:
SQL> desc dual
Name Null? Type
------------------------------- -------- ----
DUMMY VARCHAR2(1)
SQL> select sysdate from dual;
SYSDATE
---------
22-JAN-13
SQL> select 5*5 result from dual;
RESULT
---------
25
SQL> select 'Ankita' as "Name" from dual;
Name
------
Ankita
Clearly "SYSDATE" is of DATE type (not varchar2), "RESULT" is of NUMBER type (not varchar2). Also 'Ankita' is more than 1 single character, i.e., 6 characters. This should contradict the structure that varchar2 is holding only 1, and supporting 6 too..
The types and sizes of columns only come into play when you extract the data from them. It's true that if you select the dummy column, it will only give you what is in that column.
But, when you're selecting something unrelated to the column data, such as 5*5 or 'Ankita', they have no such restrictions.
I think your misunderstanding stems from your snippet:
why it can hold any datatype temporarily AND If we insert characters more than 1 (size), how this is possible for it (dual) to accept it ?
The truth is, the column doesn't accept it. Selecting 5*5 does not attempt to place that data into the table somewhere, it just evaluates it as-is. It's no different to having a table with:
users:
id
name
and performing:
select 42, 3.14159, id, name from users
For every row selected from, you will see the constant values 42 and 3.14159, alongside the data extracted from the two specified columns.