generate Multiple UUID Oracle - oracle

Oracle:-
I have around 850 records in an table, that need to be assigned UUID.
I am using the following query.
select substr(sys_guid(),1,3)||'-'||
substr(sys_guid(),4,4)||'-'||
substr(sys_guid(),8,4)||'-'||
substr(sys_guid(),13)
from (select sys_guid() as mygid from dual)
I need to generate multiple/850 records in one go.
Any suggestions ?
Should I loop over?

If you really need select, use hierarchical query:
SELECT Substr(mygid,1,3)||'-'||
Substr(mygid,4,4)||'-'||
Substr(mygid,8,4)||'-'||
Substr(mygid,12)
FROM (
SELECT Sys_GUID() AS mygid FROM dual
CONNECT BY Level <= :desired_number_of_records
)
But what's wrong with usual update ?
UPDATE your_tab
SET gid_col = (
SELECT Substr(mygid,1,3)||'-'||
Substr(mygid,4,4)||'-'||
Substr(mygid,8,4)||'-'||
Substr(mygid,12)
FROM( SELECT Sys_Guid() AS mygid FROM dual )
)

Not sure that format is really what you want as you are missing 9 of the 32 characters, buy you could modify the format as needed. Here is an example that shows how to format like XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX:
UPDATE MY_TABLE
SET GUID_COL = (
select regexp_replace((rawtohex(sys_guid()), '([A-F0-9]{8})([A-F0-9]{4})([A-F0-9]{4})([A-F0-9]{4})([A-F0-9]{12})', '\1-\2-\3-\4-\5') as FORMATTED_GUID from dual
)

Related

Using a CTE to update in Oracle

For logistic reasons, I want to set a value in a CTE to use in an UPDATE statement. Here is a simplified version:
with vars as (select 5 as n from dual)
update test set data=data*vars.n, more=more*vars.n;
Of course, in real life, the CTE will calculate a value from another source, but this should make the point.
I have sample at https://dbfiddle.uk/tUJoX5uw .
I get the error
ORA-00928: missing SELECT keyword
Is it possible to use a CTE this way for an UPDATE statement?
I know about some other SO questions, but generally they either end up using MERGE, or say that you can’t update the CTE itself. I don’t want to update the CTE, just to use the results. This is a question about the UPDATE statement.
Update
I have accepted an answer below. Here is a simplified version of the solution:
UPDATE TEST t
SET (t.data, t.more) = (
SELECT vars.n*t.data, vars.n*t.more FROM (
SELECT 5 AS n FROM dual
) vars
);
This will not work:
UPDATE TEST t SET (t.data, t.more) = (
WITH VARS(n) AS (
select 5 FROM DUAL
)
SELECT v.n * t.data, v.n * t.more
FROM vars v
)
;
SQL Error: ORA-01767: UPDATE ... SET expression must be a subquery
But this works:
UPDATE TEST t SET (t.data, t.more) = (
SELECT (select 5 from dual) * t.data, (select 5 from dual) * t.more
FROM DUAL
)
;
The WITH should be inside the SET
UPDATE test SET data = (
WITH vars(n) AS (
select 5 FROM DUAL
)
SELECT v.n * t.data
FROM vars v
)
;

Using a CTE table as part of `START WITH` clause in recursive query

I don't seem to be able to use a CTE table as part of the below recursive query?
I have two CTE tables. One that gets a bunch of grouper codes and another that explodes those grouper codes out into the "child codes" (exploded_codes) that I want to use in the below query. When I add the EXPLODED_CODES CTE table into the IN() clause of my main query (shown below), no data is returned (no error though). However, if I hard code the values that are returned from a simple select statement on the EXPLODED_CODES CTE table, into the IN() clause, the query returns as expected! Any clue why this may be?
Here is my recursive query. Is there any reason anyone can think of that using the CTE table wouldnt work, but hard coding the values that the CTE table contains would? I know it has something to do with the recursion logic because when I change starts with to where and comment out the connect by clause, it returns some data (although its not the full parent-child hierarchy that the recursive query returns using the hard coded values.
select *
from events
start with
events.event_cd in (
select event_cd from exploded_codes --This code returns no data
--22600750,135148330,107919568 --These are the values in the CTE and returns correct data
)
connect by nocycle ((prior parent_event_id = event_id and prior event_id <> event_id)
or (prior event_id = parent_event_id) )
This is essentially all I am trying to do. However, it works fine in my mock ups like this:
with mytable as (
select 1 as pk1, 123 as event_id, 123 as parent_event_id, 777 as event_cd from dual
union select 2, 456, 123, 777 as event_cd from dual
union select 3, 756, 423, 999 as event_cd from dual
)
--select * from mytable
, codes as (
select 777 as event_cd from dual union select 88 as event_cd from dual union
select 111 as event_cd from dual
)
select myTable.*--, level, SYS_CONNECT_BY_PATH(event_id, '/') as path
from
myTable
start with event_cd in (select event_cd from codes)
connect by nocycle (prior parent_event_id = event_id and prior event_id <> event_id)
or (prior event_id = parent_event_id)
However, when I query my actual database table, it returns no rows depending on how I populate the CTE table (event though my table ends up with the same values each way.
What I cant seem to understand is that when I uncomment the below line from my CODES table, is when my recursive query doesnt return anything. However, when I hard code the values in like I am below, my recursive query returns fine. I have tried casting the datatype to NUMBER (which is how event_cd is stored in the EVENT table) and that has no affect.
with codes as (
--This method of populating the table causes my recursive query to not return anything
--select xcode from xr_template_codes where xtype = 'event-set' and SECTION_DISPLAY = 'Coding Summary'
--So does this method (which is the equivalent of the above).
--select xcode from xr_template_codes where xcode = 107919402
--union
--select xcode from xr_template_codes where xcode = 101320306
--This method seems to work fine. These are just the two values returned from the XR_TEMPLATES_CODES table.
select 101320306 as event_cd from dual union select 107919402 as event_cd from dual
)
select *
from
event
start with
event.event_cd in (select to_number(event_cd) from codes)
and event.id = 15169295
connect by nocycle (prior parent_event_id = event_id and prior event_id <> event_id)
or (prior event_id = parent_event_id)

Using a single select statment to get the next row from a table or return the first row if the end of table is reached

I have a table say STAFF like below:
STAFF_NAME
============
ALEX
BERNARD
CARL
DOMINIC
EMMA
Now, I want to write a stored function with a single argument. E.g. GET_NEXT_STAFF(CURRENT_STAFF).
The input and output should be like:
Input | Output
=====================
NULL | ALEX
ALEX | BERNARD
BERNARD | CARL
EMMA | ALEX (Start from the beginning of the table again)
I know how to handle this problem using PL/SQL, but is it possible to deal with this problem with a single select statement?
In the solution below, I assume the rows are ordered alphabetically by names. They may be ordered by another column in the same table (for example by hire date, or by salary, etc. - it doesn't matter) - then the name of that column should be used in the ORDER BY clause of the two analytic functions.
The input name is passed in as a bind variable, :input_staff_name. The solution uses pure SQL, with no need for functions (PL/SQL), but if you must make it into a function, you can adapt it easily.
Edit: In my original answer I missed the required behavior when the input is null. The last line of code (excluding the semicolon) takes care of that. As written currently, the query returns ALEX (or in general the first value in the table) when the input is null, and it returns no rows when the input is not null and not in the table. If instead the requirement is to return the first name when the input is null or not found in the table, then it can be accommodated easily by removing and :input_staff_name is null from the last line.
with
tbl ( staff_name ) as (
select 'ALEX' from dual union all
select 'BERNARD' from dual union all
select 'CARL' from dual union all
select 'DOMINIC' from dual union all
select 'EMMA' from dual
),
prep ( staff_name, next_name, first_name ) as (
select staff_name,
lead(staff_name) over (order by staff_name),
first_value (staff_name) over (order by staff_name)
from tbl
)
select nvl(next_name, first_name) as next_staff_name
from prep
where staff_name = :input_staff_name
or (next_name is null and :input_staff_name is null)
;
Based on the answer from #mathguy I have made a few changes that seem to work. I have added the follow
UNION ALL
SELECT NULL
FROM DUAL
and
WHERE NVL (staff_name, 'X') = NVL (NULL, 'X');
The full code
WITH tbl (staff_name) AS
(SELECT 'ALEX' FROM DUAL
UNION ALL
SELECT 'BERNARD' FROM DUAL
UNION ALL
SELECT 'CARL' FROM DUAL
UNION ALL
SELECT 'DOMINIC' FROM DUAL
UNION ALL
SELECT 'EMMA' FROM DUAL
UNION ALL
SELECT NULL
FROM DUAL),
prep (staff_name,
next_name,
first_name,
last_name) AS
(SELECT staff_name,
LEAD (staff_name) OVER (ORDER BY staff_name),
FIRST_VALUE (staff_name) OVER (ORDER BY staff_name),
LAG (staff_name) OVER (ORDER BY staff_name)
FROM tbl)
SELECT NVL (next_name, first_name) AS next_staff_name
FROM prep
WHERE NVL (staff_name, 'X') = NVL (:input_staff_name, 'X');

Use sequence number with insert select

I'm trying to execute the following statement:
INSERT INTO mySchema.ODI_PRICELIST_THREAD_TABLE
(
src_table,
thread_id,
creation_date
)
SELECT DISTINCT
source_table AS src_table,
num_thread_seq.nextval AS THREAD_ID,
create_date AS CREATION_DATE
FROM mySchema.nb_pricelist_ctrl
I need the THREAD_ID field to be a number from 1 to X where X is defined in runtime therefore I've used a sequence from 1 to X (I'm using ODI).
However, I keep having the ORA-02287 Sequence not allowed error...
I've read this question and I still can't figure how I can fix my problem.
I've been seaching but I'm having no luck with finding a solution. Please help
Keyword distinct is incompatible with sequence querying. If you really need it, try something like
INSERT INTO mySchema.ODI_PRICELIST_THREAD_TABLE (
src_table,
thread_id,
creation_date)
select
a.src_table,
num_thread_seq.nextval,
a.create_date
from
(select distinct src_table, create_date from mySchema.nb_pricelist_ctrl) a
From OraFaq :
The following are the cases where you can't use a sequence:
For a SELECT Statement:
In a WHERE clause
In a GROUP BY or ORDER BY clause
In a DISTINCT clause
Along with a UNION or INTERSECT or MINUS
In a sub-query
http://www.orafaq.com/wiki/ORA-02287
Try this
INSERT INTO mySchema.ODI_PRICELIST_THREAD_TABLE
(
src_table,
thread_id,
creation_date
)
SELECT DISTINCT
source_table AS src_table,
num_thread_seq.nextval() AS THREAD_ID,
create_date AS CREATION_DATE
FROM mySchema.nb_pricelist_ctrl

Is Numeric in Oracle

I'm working in oracle 11g. I've a table with Number as the datatype. For development purpose we have created a staging table with varchar type. Initially data would be loaded in the staging table. We need find out the records that has only number in that column, since the data might contain the noises. Is there any way to find it.
You can select your data with a regexp_like :
SELECT *
FROM your_table t
WHERE REGEXP_LIKE (t.your_colonne, '^[0-9]+$');
The regexp_like function can be used to determine if a value consists of only digits. Here is an example:
with Your_table(your_column) as(
select '123456' from dual union all
select 'a123452' from dual union all
select '01456' from dual union all
select '1j6-d' from dual
)
select your_column
from your_table
where regexp_like(your_column, '^[[:digit:]]+$')
Result:
YOUR_COLUMN
--------------
123456
01456
SQL Fiddle Demo

Resources