Why Simple Oracle Update Statement Make Block Session? - oracle

I have simple Oracle (19C) update statement like this and it is making block sessions some times. This update query is running from an ASP.NET MVC System which uses Entity Framework. Since I am new to this issue, Can anyone provide me an idea how I can figure out the exact issue, what can be the reason and how can I resolve it?
UPDATE "TICKET_TRACKINGPRD"."TKT_TICKET"
SET
"TITLE" = :b22,
"SUMMARY" = :b21,
"DESCRIPTION" = :b20,
"ENVIRONMENT" = :b19,
"TICKET_PROJECT_ID" = :b18,
"TICKET_PROJECT_MODULE_ID" = NULL,
"APPLICATION_TYPE_ID" = :b17,
"APPLICATION_ID" = :b16,
"APPLICATION_MODULE_ID" = :b15,
"APPLICATION_SERVICE_ID" = :b14,
"SERVICE_CHANNEL_ID" = :b13,
"TICKET_STATUS_ID" = :b12,
"TICKET_RESOLUTION_ID" = :b11,
"TICKET_PRIORITY_ID" = :b10,
"ASSIGNEE_ID" = :b9,
"DUE_DATE" = :b8,
"REPORTED_BY_USER_NAME" = :b7,
"USER_LANGUAGE_ID" = :b6,
"CLOSED_DATE" = NULL,
"CLOSED_BY_USER_ID" = NULL,
"CONTEXT_KEY" = NULL,
"CONTEXT_URL" = NULL,
"CREATED_DATE" = :b5,
"MODIFIED_DATE" = :b4,
"CREATED_BY_USER_ID" = :b3,
"MODIFIED_BY_USER_ID" = :b2,
"RECORD_STATUS_ID" = :b1
WHERE
("ID" = :b23)
RETURNING "KEY" INTO : o0

I'm not saying that this is "it", but ... might be.
what can be the reason
Looks like the unindexed foreign keys issue. Basically, all foreign key columns should be indexed. As documentation says:
Indexing the foreign keys in child tables provides the following benefits:
Prevents a full table lock on the child table. Instead, the database acquires a row lock on the index.
For more info, read Locks and foreign keys.
and how can I resolve it?
Obviously, by indexing foreign key columns. But, first you have to find them. I use Tom Kyte's script (adjusted a little bit):
/* 12.12.2012. Tom Kyte: locating unindexed foreign keys
14.03.2016. PAR_WHAT: 0 - show those that aren't OK
1 - show those that are OK
NULL - show all
*/
WITH forkey
AS (SELECT DECODE (b.table_name, NULL, '****', 'ok') Status,
a.table_name,
a.columns column_1,
b.columns column_2
FROM ( SELECT SUBSTR (a.table_name, 1, 30) table_name,
SUBSTR (a.constraint_name, 1, 30) constraint_name,
MAX (
DECODE (position,
1, SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (position,
2, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (position,
3, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (position,
4, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (position,
5, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (position,
6, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (position,
7, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (position,
8, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (position,
9, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
position,
10, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
position,
11, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
position,
12, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
position,
13, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
position,
14, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
position,
15, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
position,
16, ', ' || SUBSTR (column_name, 1, 30),
NULL))
columns
FROM user_cons_columns a, user_constraints b
WHERE a.constraint_name = b.constraint_name
AND b.constraint_type = 'R'
GROUP BY SUBSTR (a.table_name, 1, 30),
SUBSTR (a.constraint_name, 1, 30)) a,
( SELECT SUBSTR (table_name, 1, 30) table_name,
SUBSTR (index_name, 1, 30) index_name,
MAX (
DECODE (column_position,
1, SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (column_position,
2, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (column_position,
3, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (column_position,
4, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (column_position,
5, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (column_position,
6, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (column_position,
7, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (column_position,
8, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (column_position,
9, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
column_position,
10, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
column_position,
11, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
column_position,
12, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
column_position,
13, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
column_position,
14, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
column_position,
15, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
column_position,
16, ', ' || SUBSTR (column_name, 1, 30),
NULL))
columns
FROM user_ind_columns
GROUP BY SUBSTR (table_name, 1, 30),
SUBSTR (index_name, 1, 30)) b
WHERE a.table_name = b.table_name(+)
AND b.columns(+) LIKE a.columns || '%'
AND a.table_name NOT LIKE 'HEP_DP%')
SELECT f.status,
f.table_name,
f.column_1,
f.column_2
FROM forkey f
WHERE f.status =
CASE
WHEN :par_what = 1 THEN 'ok'
WHEN :par_what = 0 THEN '****'
ELSE f.status
END
ORDER BY f.table_name, f.column_1, f.column_2
/
For example:
SQL> create table a (id number primary key);
Table created.
SQL> create table b (id number constraint fk_ba references a (id));
Table created.
Table B misses index on its foreign key constraint column, so query returns:
SQL> /
STATUS TABLE_NAME COLUMN_1 COLUMN_2
---------- ---------- ---------- ----------
**** B ID
Create an index:
SQL> create index a1bid on b (id);
Index created.
Query doesn't return anything now:
SQL> /
no rows selected
See if it helps.

Related

How can I split by a character without ignoring nulls?

I'm trying to use regexp_subst to split a delimited string. I'm running into an issue when delimited fields are null. The regexp_substr ignores the nulls and moves to the next occurrence of the delimiter. Is there a way to do this with regexp_substr? If not, what alternative do you use?
--Expecting hello, gets hello
select regexp_substr('hello##world', '[^#]+', 1, 1)
from dual;
--Expecting null, gets world
select regexp_substr('hello##world', '[^#]+', 1, 2)
from dual;
--Expecting world, gets null
select regexp_substr('hello##world', '[^#]+', 1, 3)
from dual;
EDIT: tried this, but it works only with | which isn't an option
Answering based on Matbailie's input in above comment
select regexp_substr('hello##world', '(.*?)(#|$)', 1, 1,NULL,1)
from dual
union all
--Expecting null, gets null
select regexp_substr('hello##world', '(.*?)(#|$)', 1, 2,NULL,1)
from dual
union all
--Expecting world, gets world
select regexp_substr('hello##world', '(.*?)(#|$)', 1, 3,NULL,1)
from dual;
You do not need regular expressions. It can be done with simple (and faster) string functions in a recursive sub-query:
WITH data (value) AS (
SELECT 'hello##world' FROM DUAL
),
bounds (value, start_pos, end_pos) AS (
SELECT value,
1,
INSTR(value, '#', 1)
FROM data
UNION ALL
SELECT value,
end_pos + 1,
INSTR(value, '#', end_pos + 1)
FROM bounds
WHERE end_pos > 0
)
SEARCH DEPTH FIRST BY value SET order_id
SELECT CASE end_pos
WHEN 0
THEN SUBSTR(value, start_pos)
ELSE SUBSTR(value, start_pos, end_pos - start_pos)
END AS item
FROM bounds;
Which outputs:
ITEM
hello
null
world
Or, if you want the data in columns (rather than rows):
WITH data (value) AS (
SELECT 'hello##world' FROM DUAL
),
bounds (value, pos1, pos2) AS (
SELECT value,
INSTR(value, '#', 1, 1),
INSTR(value, '#', 1, 2)
FROM data
)
SELECT SUBSTR(value, 1, pos1 - 1) AS item1,
SUBSTR(value, pos1 + 1, pos2 - pos1 - 1) AS item2,
SUBSTR(value, pos2 + 1) AS item3
FROM bounds
Which outputs:
ITEM1
ITEM2
ITEM3
hello
null
world
If you did want to use (slower) regular expressions then:
WITH data (value) AS (
SELECT 'hello##world' FROM DUAL
)
SELECT item
FROM data d
CROSS JOIN LATERAL(
SELECT REGEXP_SUBSTR( d.value, '(.*?)(#|$)', 1, LEVEL, NULL, 1) AS item
FROM DUAL
CONNECT BY LEVEL < REGEXP_COUNT( d.value, '(.*?)(#|$)')
)
or, for columns:
WITH data (value) AS (
SELECT 'hello##world' FROM DUAL
)
SELECT REGEXP_SUBSTR(value, '(.*?)(#|$)', 1, 1, NULL, 1) AS item1,
REGEXP_SUBSTR(value, '(.*?)(#|$)', 1, 2, NULL, 1) AS item2,
REGEXP_SUBSTR(value, '(.*?)(#|$)', 1, 3, NULL, 1) AS item3
FROM data
(Which both have the same output as above)
db<>fiddle here

avoid hung sessions in oracle

I have a procedure in pl/sql which works fine with small amount of data. The issue is, when is a large amount of data, cursor6 sometimes hangs session and other users can't access table5.
table5 has a primary key column "ocf" which is the user id, so each user access only rows coresponding his user id. Even under these conditions, the cursor6 locks the table5 and create a dead session and, I don't understand how, but it doesn't allow other users to access it
even if they use other rows in table5. Is there a solution to recreate that cursor for update or use something that may do the same thing, avoiding in this way that hanging session?
cursor cursor6(pf varchar2,PO number, psu varchar2) is select * from table5 where ocf=PO and .. for update;
row1 cursor6%rowtype;
BEGIN
delete table5 where ocf=PO;
commit;
open cursor1;
fetch cursor1 into wv,wd;
if cursor1%found then
open cursor2;
fetch cursor2 into wf;
if cursor2%found then
while cursor2%found loop
open cursor3;
fetch cursor3 into wco;
if cursor3%found then
while cursor3%found loop
open cursor5;
fetch cursor5 into ws;
while cursor5%found loop
open cursor4;
fetch cursor4 into ..;
if cursor4%found then
open cursor6(..);
fetch cursor6 into row1;
if cursor6%notfound then insert into table5 values (..);
else update table5 set ... where current of cursor6;
end if;
close cursor6;
end if;
close cursor4;
end loop;
close cursor5;
end loop;
end if;
close cursor3;
end loop;
end if;
close cursor2;
end if;
close cursor1;
commit;
delete table5 where ocf=PO;
commit;
Gosh, good luck with 6 nested loops.
cursor6 locks the table5 and create a dead session and, I don't understand how, but it doesn't allow other users to acces
That happens when foreign key columns aren't indexed. I suggest you check whether that's the case and - if so - create indexes.
Here's a query (author is Tom Kyte) (I don't have a link to the original, sorry; Google for it if you want) which displays unindexed foreign key constraints. I modified it a little bit by adding what to display:
PAR_WHAT:
0 - show only missing ones
1 - show valid ones
NULL - show all
I suggest you first run it with PAR_WHAT = 0.
WITH forkey
AS (SELECT DECODE (b.table_name, NULL, '****', 'ok') Status,
a.table_name,
a.columns column_1,
b.columns column_2
FROM ( SELECT SUBSTR (a.table_name, 1, 30) table_name,
SUBSTR (a.constraint_name, 1, 30) constraint_name,
MAX (
DECODE (position,
1, SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (position,
2, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (position,
3, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (position,
4, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (position,
5, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (position,
6, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (position,
7, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (position,
8, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (position,
9, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
position,
10, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
position,
11, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
position,
12, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
position,
13, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
position,
14, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
position,
15, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
position,
16, ', ' || SUBSTR (column_name, 1, 30),
NULL))
columns
FROM user_cons_columns a, user_constraints b
WHERE a.constraint_name = b.constraint_name
AND b.constraint_type = 'R'
GROUP BY SUBSTR (a.table_name, 1, 30),
SUBSTR (a.constraint_name, 1, 30)) a,
( SELECT SUBSTR (table_name, 1, 30) table_name,
SUBSTR (index_name, 1, 30) index_name,
MAX (
DECODE (column_position,
1, SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (column_position,
2, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (column_position,
3, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (column_position,
4, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (column_position,
5, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (column_position,
6, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (column_position,
7, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (column_position,
8, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (column_position,
9, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
column_position,
10, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
column_position,
11, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
column_position,
12, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
column_position,
13, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
column_position,
14, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
column_position,
15, ', ' || SUBSTR (column_name, 1, 30),
NULL))
|| MAX (
DECODE (
column_position,
16, ', ' || SUBSTR (column_name, 1, 30),
NULL))
columns
FROM user_ind_columns
GROUP BY SUBSTR (table_name, 1, 30),
SUBSTR (index_name, 1, 30)) b
WHERE a.table_name = b.table_name(+)
AND b.columns(+) LIKE a.columns || '%'
AND a.table_name NOT LIKE 'HEP_DP%')
SELECT f.status,
f.table_name,
f.column_1,
f.column_2
FROM forkey f
WHERE f.status =
CASE
WHEN :par_what = 1 THEN 'ok'
WHEN :par_what = 0 THEN '****'
ELSE f.status
END
ORDER BY f.table_name, f.column_1, f.column_2;

Split column in Oracle

I have a column in an Oracle Database which has something like this data
column1
/opt/log/data/abcd.efghi.jklmn.aaa.txt
/opt/log/data/abbbcd.efccghi.jkdsdflmn.abab.txt
/opt/log/data/nmvcnmcd.efjhjghi.jkvslmn.abcbc.txt
/opt/log/data/hjsdhj.hjfdhdf.hdfhjd.aghag.txt
/opt/log/data/dfhjfdhj.yureyer.qwtyq.hjahjh.txt
I want to split the data in such a way that
**firstdot seconddot thirdnfourthdot**
abcd efghi jklmn.aaa
abbbcd efccghi jkdsdflmn.abab
nmvcnmcd efjhjghi jkvslmn.abcbc
hjsdhj hjfdhdf hdfhjd.aghag
dfhjfdhj yureyer qwtyq.hjahjh
I can get the seconddot value by
select substr(column1,instr(column1,'.',1+1,instr(column1,'.',1,2)-instr(column1,'.',1,1)-1) as secondot
but I could not get the rest. Can you guys help.
Thanks a lot
Without regexp, you need to reply the same logic for every substring you need, every timi picking the initial position and the leght, based on the position of the "terminator" of that substring.
/* input data */
with yourTable(column1) as (
select '/opt/log/data/abcd.efghi.jklmn.aaa.txt' from dual union all
select '/opt/log/data/abbbcd.efccghi.jkdsdflmn.abab.txt' from dual union all
select '/opt/log/data/nmvcnmcd.efjhjghi.jkvslmn.abcbc.txt' from dual union all
select '/opt/log/data/hjsdhj.hjfdhdf.hdfhjd.aghag.txt' from dual union all
select '/opt/log/data/dfhjfdhj.yureyer.qwtyq.hjahjh.txt' from dual
)
/* query */
select substr(column1, instr(column1, '/', -1) +1, instr(column1, '.') - instr(column1, '/', -1)-1) firstDot,
substr(column1, instr(column1, '.') +1, instr(column1, '.', 1, 2) - instr(column1, '.') -1) secondDot,
substr(column1, instr(column1, '.', 1, 2) +1, instr(column1, '.', 1, 4) - instr(column1, '.', 1, 2) -1) thirdAndFourthDot
from yourTable
gives:
FIRSTDOT SECONDDOT THIRDANDFOURTHD
--------------- --------------- ---------------
abcd efghi jklmn.aaa
abbbcd efccghi jkdsdflmn.abab
nmvcnmcd efjhjghi jkvslmn.abcbc
hjsdhj hjfdhdf hdfhjd.aghag
dfhjfdhj yureyer qwtyq.hjahjh
In a more readable way:
select substr(column1, lastSlashPos +1, firstDotPos - lastSlashPos -1) as firstDot,
substr(column1, firstDotPos +1, secondDotPos - firstDotPos -1) as secondDot,
substr(column1, secondDotPos +1, fourthDotPos - secondDotPos -1) as thirdAndFourthDot
from (
select instr(column1, '/', -1) as lastSlashPos,
instr(column1, '.') as firstDotPos,
instr(column1, '.', 1, 2) as secondDotPos,
instr(column1, '.', 1, 3) as thirdDotPos,
instr(column1, '.', 1, 4) as fourthDotPos,
column1
from yourTable
)
select substr('/opt/log/data/abcd.efghi.jklmn.aaa.txt',instr('/opt/log/data/abcd.efghi.jklmn.aaa.txt','/',-1) + 1) from dual;
This will give you text after last /
Then you need to apply instr for .:
select
substr(text, 1, instr(text,'.', 1) - 1),
substr(text, instr(text,'.', 1) + 1, instr(text,'.', 2) - 1),
substr(text, instr(text,'.', 2) + 1)
from (
select substr('/opt/log/data/abcd.efghi.jklmn.aaa.txt',instr('/opt/log/data/abcd.efghi.jklmn.aaa.txt','/',-1) + 1) text from dual
);

Invalid number error - [Error Code: 1722, SQL State: 42000] ORA-01722: invalid number

The 1st query from the below 2 queries is giving me [Error Code: 1722, SQL State: 42000] ORA-01722: invalid number error.
But when I limit the no of records as in the 2nd query then it is running fine.
Other than limiting the rows in the 2nd query, both the queries are identical.
SELECT b.first_name,
b.last_name,
b.device_derived,
b.ios_version_group,
b.add_date,
FIRST_VALUE (b.add_date)
OVER (PARTITION BY b.first_name, b.last_name, b.ios_version_group)
AS first_date,
LAST_VALUE (b.add_date)
OVER (PARTITION BY b.first_name, b.last_name, b.ios_version_group)
AS last_date
FROM (SELECT a.first_name,
a.last_name,
a.os_version,
a.device_type,
a.device,
a.add_date,
a.device_derived,
CASE
WHEN ( ( UPPER (a.device_derived) = 'IPHONE'
OR UPPER (a.device_derived) = 'IPAD')
AND TO_NUMBER (SUBSTR (a.os_version, 1, 1)) > 4)
THEN
'iOS ' || SUBSTR (a.os_version, 1, 1)
ELSE
'Others'
END
AS ios_version_group
FROM (SELECT first_name,
last_name,
os_version,
device_type,
device,
add_date,
CASE
WHEN UPPER (device_type) = 'ANDROID'
THEN
'Android'
WHEN UPPER (device_type) = 'BB'
OR UPPER (device_type) = 'BLACKBERRY'
THEN
'Blackberry'
WHEN UPPER (device_type) = 'IOS'
AND ( SUBSTR (UPPER (device), 1, 6) = 'IPHONE'
OR SUBSTR (UPPER (device), 1, 4) = 'IPOD')
THEN
'iPhone'
WHEN UPPER (device_type) = 'IOS'
AND (SUBSTR (UPPER (device), 1, 4) = 'IPAD')
THEN
'iPad'
END
AS device_derived
FROM vw_mobile_devices_all) a) b;
SELECT b.first_name,
b.last_name,
b.device_derived,
b.ios_version_group,
b.add_date,
FIRST_VALUE (b.add_date)
OVER (PARTITION BY b.first_name, b.last_name, b.ios_version_group)
AS first_date,
LAST_VALUE (b.add_date)
OVER (PARTITION BY b.first_name, b.last_name, b.ios_version_group)
AS last_date
FROM (SELECT a.first_name,
a.last_name,
a.os_version,
a.device_type,
a.device,
a.add_date,
a.device_derived,
CASE
WHEN ( ( UPPER (a.device_derived) = 'IPHONE'
OR UPPER (a.device_derived) = 'IPAD')
AND TO_NUMBER (SUBSTR (a.os_version, 1, 1)) > 4)
THEN
'iOS ' || SUBSTR (a.os_version, 1, 1)
ELSE
'Others'
END
AS ios_version_group
FROM (SELECT first_name,
last_name,
os_version,
device_type,
device,
add_date,
CASE
WHEN UPPER (device_type) = 'ANDROID'
THEN
'Android'
WHEN UPPER (device_type) = 'BB'
OR UPPER (device_type) = 'BLACKBERRY'
THEN
'Blackberry'
WHEN UPPER (device_type) = 'IOS'
AND ( SUBSTR (UPPER (device), 1, 6) = 'IPHONE'
OR SUBSTR (UPPER (device), 1, 4) = 'IPOD')
THEN
'iPhone'
WHEN UPPER (device_type) = 'IOS'
AND (SUBSTR (UPPER (device), 1, 4) = 'IPAD')
THEN
'iPad'
END
AS device_derived
FROM vw_mobile_devices_all) a) b
WHERE ROWNUM <= 100;
Can somebody tell me why I am getting this error. Is there an efficient way to write this query?
You have TO_NUMBER (SUBSTR (a.os_version, 1, 1) in your queries, so presumably you're hitting data that doesn't have a number at the start of the os_version, when you request more than 100 rows.
You need to check your data.
This error happens when you try to convert a non-numeric value with TO_NUMBER.
In the second query the first 100 rows seem not to result into a.os_version to a non-numeric value.
Try a simple select vw_mobile_devices_all to find the non-numeric os_version. Figure out how you can work around the problem. Maybe you can query the os_version differently.

How can you tell which columns are unused in ALL_TAB_COLS?

When you query the ALL_TAB_COLS view on Oracle 9i, it lists columns marked as UNUSED as well as the 'active' table columns. There doesn't seem to be a field that explicitly says whether a column is UNUSED, or any view I can join to that lists the unused columns in a table. How can I easily find out which are the unused columns, so I can filter them out of ALL_TAB_COLS?
Try using ALL_TAB_COLUMNS instead of ALL_TAB_COLS. In Oracle 11.2 I find that unused columns appear in ALL_TAB_COLS (though renamed) but not in ALL_TAB_COLUMNS.
I created a table like this:
create table t1 (c1 varchar2(30), c2 varchar2(30);
Then set c2 unused:
alter table t1 set unused column c2;
Then I see:
select column_name from all_tab_cols where owner='ME' and table_name='T1';
COLUMN_NAME
-----------
C1
SYS_C00002_10060107:25:40$
select column_name from all_tab_columns where owner='ME' and table_name='T1';
COLUMN_NAME
-----------
C1
The only filter in the definition of ALL_TAB_COLUMNS is "where hidden_column = 'NO'", so it seems that UNUSED columns are flagged in the HIDDEN_COLUMN field.
Looking further into the data definition views, it looks like COL$.PROPERTY gets set to 32800 (bits 2^5 and 2^15) when the column becomes UNUSED. 2^5 is used to mark hidden columns, so it seems likely 2^15 is UNUSED. You could create a custom version of ALL_TAB_COLS based on that which should work for what you need, such as this.
CREATE OR REPLACE FORCE VIEW all_tab_cols_rev (owner,
table_name,
column_name,
data_type,
data_type_mod,
data_type_owner,
data_length,
data_precision,
data_scale,
nullable,
column_id,
default_length,
data_default,
num_distinct,
low_value,
high_value,
density,
num_nulls,
num_buckets,
last_analyzed,
sample_size,
character_set_name,
char_col_decl_length,
global_stats,
user_stats,
avg_col_len,
char_length,
char_used,
v80_fmt_image,
data_upgraded,
hidden_column,
virtual_column,
segment_column_id,
internal_column_id,
histogram,
qualified_col_name,
unused_column)
AS
SELECT u.NAME,
o.NAME,
c.NAME,
DECODE (c.type#,
1, DECODE (c.CHARSETFORM, 2, 'NVARCHAR2', 'VARCHAR2'),
2, DECODE (c.scale, NULL, DECODE (c.precision#, NULL, 'NUMBER', 'FLOAT'), 'NUMBER'),
8, 'LONG',
9, DECODE (c.CHARSETFORM, 2, 'NCHAR VARYING', 'VARCHAR'),
12, 'DATE',
23, 'RAW',
24, 'LONG RAW',
58, NVL2 (ac.synobj#, (SELECT o.NAME
FROM obj$ o
WHERE o.obj# = ac.synobj#), ot.NAME),
69, 'ROWID',
96, DECODE (c.CHARSETFORM, 2, 'NCHAR', 'CHAR'),
100, 'BINARY_FLOAT',
101, 'BINARY_DOUBLE',
105, 'MLSLABEL',
106, 'MLSLABEL',
111, NVL2 (ac.synobj#, (SELECT o.NAME
FROM obj$ o
WHERE o.obj# = ac.synobj#), ot.NAME),
112, DECODE (c.CHARSETFORM, 2, 'NCLOB', 'CLOB'),
113, 'BLOB',
114, 'BFILE',
115, 'CFILE',
121, NVL2 (ac.synobj#, (SELECT o.NAME
FROM obj$ o
WHERE o.obj# = ac.synobj#), ot.NAME),
122, NVL2 (ac.synobj#, (SELECT o.NAME
FROM obj$ o
WHERE o.obj# = ac.synobj#), ot.NAME),
123, NVL2 (ac.synobj#, (SELECT o.NAME
FROM obj$ o
WHERE o.obj# = ac.synobj#), ot.NAME),
178, 'TIME(' || c.scale || ')',
179, 'TIME(' || c.scale || ')' || ' WITH TIME ZONE',
180, 'TIMESTAMP(' || c.scale || ')',
181, 'TIMESTAMP(' || c.scale || ')' || ' WITH TIME ZONE',
231, 'TIMESTAMP(' || c.scale || ')' || ' WITH LOCAL TIME ZONE',
182, 'INTERVAL YEAR(' || c.precision# || ') TO MONTH',
183, 'INTERVAL DAY(' || c.precision# || ') TO SECOND(' || c.scale || ')',
208, 'UROWID',
'UNDEFINED'),
DECODE (c.type#, 111, 'REF'),
NVL2 (ac.synobj#, (SELECT u.NAME
FROM user$ u, obj$ o
WHERE o.owner# = u.user#
AND o.obj# = ac.synobj#), ut.NAME),
c.LENGTH,
c.precision#,
c.scale,
DECODE (SIGN (c.null$), -1, 'D', 0, 'Y', 'N'),
DECODE (c.col#, 0, TO_NUMBER (NULL), c.col#),
c.deflength,
c.default$,
h.distcnt,
h.lowval,
h.hival,
h.density,
h.null_cnt,
CASE
WHEN NVL (h.distcnt, 0) = 0
THEN h.distcnt
WHEN h.row_cnt = 0
THEN 1
WHEN ( h.bucket_cnt > 255
OR ( h.bucket_cnt > h.distcnt
AND h.row_cnt = h.distcnt
AND h.density * h.bucket_cnt <= 1) )
THEN h.row_cnt
ELSE h.bucket_cnt
END,
h.timestamp#,
h.sample_size,
DECODE (c.CHARSETFORM,
1, 'CHAR_CS',
2, 'NCHAR_CS',
3, NLS_CHARSET_NAME (c.CHARSETID),
4, 'ARG:' || c.CHARSETID),
DECODE (c.CHARSETID, 0, TO_NUMBER (NULL), NLS_CHARSET_DECL_LEN (c.LENGTH, c.CHARSETID) ),
DECODE (BITAND (h.spare2, 2), 2, 'YES', 'NO'),
DECODE (BITAND (h.spare2, 1), 1, 'YES', 'NO'),
h.avgcln,
c.spare3,
DECODE (c.type#,
1, DECODE (BITAND (c.property, 8388608), 0, 'B', 'C'),
96, DECODE (BITAND (c.property, 8388608), 0, 'B', 'C'),
NULL),
DECODE (BITAND (ac.flags, 128), 128, 'YES', 'NO'),
DECODE (o.status,
1, DECODE (BITAND (ac.flags, 256), 256, 'NO', 'YES'),
DECODE (BITAND (ac.flags, 2),
2, 'NO',
DECODE (BITAND (ac.flags, 4), 4, 'NO', DECODE (BITAND (ac.flags, 8), 8, 'NO', 'N/A') ) ) ),
DECODE (c.property, 0, 'NO', DECODE (BITAND (c.property, 32), 32, 'YES', 'NO') ),
DECODE (c.property, 0, 'NO', DECODE (BITAND (c.property, 8), 8, 'YES', 'NO') ),
DECODE (c.segcol#, 0, TO_NUMBER (NULL), c.segcol#),
c.intcol#,
CASE
WHEN NVL (h.row_cnt, 0) = 0
THEN 'NONE'
WHEN ( h.bucket_cnt > 255
OR ( h.bucket_cnt > h.distcnt
AND h.row_cnt = h.distcnt
AND h.density * h.bucket_cnt <= 1) )
THEN 'FREQUENCY'
ELSE 'HEIGHT BALANCED'
END,
DECODE (BITAND (c.property, 1024),
1024, (SELECT DECODE (BITAND (cl.property, 1), 1, rc.NAME, cl.NAME)
FROM SYS.col$ cl, attrcol$ rc
WHERE cl.intcol# = c.intcol# - 1
AND cl.obj# = c.obj#
AND c.obj# = rc.obj#(+)
AND cl.intcol# = rc.intcol#(+)),
DECODE (BITAND (c.property, 1), 0, c.NAME, (SELECT tc.NAME
FROM SYS.attrcol$ tc
WHERE c.obj# = tc.obj#
AND c.intcol# = tc.intcol#) ) ),
DECODE (c.property, 0, 'NO', DECODE (BITAND (c.property, 32768), 32768, 'YES', 'NO') )
FROM SYS.col$ c, SYS.obj$ o, SYS.hist_head$ h, SYS.user$ u, SYS.coltype$ ac, SYS.obj$ ot, SYS.user$ ut
WHERE o.obj# = c.obj#
AND o.owner# = u.user#
AND c.obj# = h.obj#(+)
AND c.intcol# = h.intcol#(+)
AND c.obj# = ac.obj#(+)
AND c.intcol# = ac.intcol#(+)
AND ac.toid = ot.oid$(+)
AND ot.type#(+) = 13
AND ot.owner# = ut.user#(+)
AND ( o.type# IN (3, 4) /* cluster, view */
OR ( o.type# = 2 /* tables, excluding iot - overflow and nested tables */
AND NOT EXISTS (
SELECT NULL
FROM SYS.tab$ t
WHERE t.obj# = o.obj#
AND ( BITAND (t.property, 512) = 512
OR BITAND (t.property, 8192) = 8192) ) ) )
AND ( o.owner# = USERENV ('SCHEMAID')
OR o.obj# IN (SELECT obj#
FROM SYS.objauth$
WHERE grantee# IN (SELECT kzsrorol
FROM x$kzsro) )
OR /* user has system privileges */
EXISTS (
SELECT NULL
FROM v$enabledprivs
WHERE priv_number IN
(-45 /* LOCK ANY TABLE */,
-47 /* SELECT ANY TABLE */,
-48 /* INSERT ANY TABLE */,
-49 /* UPDATE ANY TABLE */,
-50 /* DELETE ANY TABLE */) ) );
I'd put the view in a separate, locked schema that has the SELECT ANY DICTIONARY privilege, then create a public synonym for it. That way, all of your users would be able to see the UNUSED_COLUMN column for only the tables that they have permissions on.

Resources