DBMS_LOCK how to find LOCKID by NAME - oracle

My task is to show for oracle forms user session id of some locked object in oracle database. It is possible get from select (l1.name is known value):
SELECT l2.SID
FROM SYS.DBMS_LOCK_ALLOCATED l1,
gv$lock l2
WHERE l1.lockid = l2.ID1
AND l1.name = 'OBJECT_NAME'
The problem is that our oracle forms users have not access to the table SYS.DBMS_LOCK_ALLOCATED. Package DBMS_LOCK has no function to find SYS.DBMS_LOCK_ALLOCATED.LOCKID by SYS.DBMS_LOCK_ALLOCATED.NAME.
Someone have ideas on how to solve this problem?

You can use the following query to get lock status of object:
select oracle_username || ' (' || s.osuser || ')' username
, s.sid || ',' || s.serial# sess_id
, owner || '.' || object_name object
, object_type
, decode( l.block
, 0, 'Not Blocking'
, 1, 'Blocking'
, 2, 'Global') status
, decode(v.locked_mode
, 0, 'None'
, 1, 'Null'
, 2, 'Row-S (SS)'
, 3, 'Row-X (SX)'
, 4, 'Share'
, 5, 'S/Row-X (SSX)'
, 6, 'Exclusive', TO_CHAR(lmode)) mode_held
from v$locked_object v
, dba_objects d
, v$lock l
, v$session s
where v.object_id = d.object_id
and v.object_id = l.id1
and v.session_id = s.sid
and d.object_name = '<My table>'
and d.owner = '<Owner>'
Note: I left v$-views but if You are using RAC and want to see all the instances here then just change v$ on gv$.
You can check output of the query above after doing:
create table my_table as select 1 val from dual;
lock table my_table in exclusive mode;
P.S. Don't forget to hit commit to unlock my_table.

Related

ORA-01722: invalid number in Update query

I have following query and getting ORA-01722: invalid number
UPDATE SCHEDULE SET IS_ACTIVE = 0 WHERE REMINDER_ID IN ( SELECT replace('1,2', '''', '') as xtx FROM DUAL);
When I tried following way it executes , SELECT replace('1,2', '''', '') FROM DUAL;
I am getting (1,2) but this is not happening in the first query.
Got it and working - x_reminder_id = "'12,13'"
MERGE INTO SCHEDULE dst
USING (
SELECT REGEXP_SUBSTR(x_reminder_id, '\d+', 1, LEVEL) AS id
FROM DUAL
CONNECT BY LEVEL <= LEAST(
REGEXP_COUNT(x_reminder_id, '\d+')
)
) src
ON (src.id = dst.REMINDER_ID)
WHEN MATCHED THEN
UPDATE
SET IS_ACTIVE = 0;

Find session of locked row

I am experiencing row lock contention in my oracle DB. I tried to kill some session to unlock them, but this rows are still locked.
I know exact which row are locked.
Can I find the session ID that has locked this row. I can get the ROWID of that row.
As the good folks on AskTom say, we don't maintain a list of locked rows
But, if you want to try this - it'll show you locks by USER in your database, including Row locks.
SELECT
p.username username,
p.pid pid,
s.sid sid,
s.serial# serial,
p.spid spid,
s.username ora,
DECODE(l2.type, 'TX', 'TRANSACTION ROW-LEVEL', 'RT', 'REDO-LOG', 'TS', 'TEMPORARY SEGMENT ', 'TD', 'TABLE LOCK', 'TM', 'ROW LOCK'
, l2.type) vlock,
DECODE(l2.type, 'TX', 'DML LOCK', 'RT', 'REDO LOG', 'TS', 'TEMPORARY SEGMENT', 'TD', DECODE(l2.lmode + l2.request, 4, 'PARSE '
|| u.name || '.' || o.name, 6, 'DDL', l2.lmode + l2.request), 'TM', 'DML ' || u.name || '.' || o.name, l2.type) type,
DECODE(l2.lmode + l2.request, 2, 'RS', 3, 'RX', 4, 'S', 5, 'SRX', 6, 'X', l2.lmode + l2.request) lmode,
DECODE(l2.request, 0, NULL, 'WAIT') wait
FROM
gv$process p,
gv$_lock l1,
gv$lock l2,
gv$resource r,
sys.obj$ o,
sys.user$ u,
gv$session s
WHERE
s.paddr = p.addr
AND s.saddr = l1.saddr
AND l1.raddr = r.addr
AND l2.addr = l1.laddr
AND l2.type <> 'MR'
AND r.id1 = o.obj# (+)
AND o.owner# = u.user# (+)
--AND u.name = 'GME'
AND ( :user_name IS NULL
OR s.username LIKE upper(:user_name) )
ORDER BY
p.username,
p.pid,
p.spid,
ora,
DECODE(l2.type, 'TX', 'TRANSACTION ROW-LEVEL', 'RT', 'REDO-LOG', 'TS', 'TEMPORARY SEGMENT ', 'TD', 'TABLE LOCK', 'TM', 'ROW LOCK'
, l2.type)
This is a report in SQL Developer.

plsql procedure to compare two tables without any primary key column

Have to compare the data differences between the below two tables. I have achieved this by writing a MINUS query but that does not fit for current assignment. Because few tables have 50- 60 columns and each time have to mention the columns before execution.
I have followed Expert's response and not succeeded in achieving the goal. Basically I want to write a procedure which:
Accepts both table names as parameters.
Fetch all the columns of CustomerTable.
Then MINUS query between CustomerTable and StagingCustTable only with the columns fetched in step-2.
Logging any differences.
CustomerTable
Custromer_Number
Address
order_Number
Contact
Country
Post_Code
Amount
StagingCustTable
Custromer_Number
Address
order_Number
Contact
Country
Post_Code
Amount
Run_Id
Record_Id
I would not use a procedure but a query to generate a final query.
Kind of dynamic SQL.
Simple example - let say we have the following tables and data in them:
CREATE TABLE CustomerTable(
Custromer_Number int,
Address varchar2(100),
order_Number int,
Contact int,
Country varchar2(10),
Post_Code varchar2(10),
Amount number
);
INSERT ALL
INTO CustomerTable VALUES (1, 'aaa', 1, 1, 'AA', '111', 111.11 )
INTO CustomerTable VALUES (2, 'bbb', 2, 2, 'BB', '222', 222.22 )
SELECT 1 FROM dual;
CREATE TABLE StagingCustTable
AS SELECT t.*, 1 As run_id, 1 as record_id
FROM CustomerTable t
WHERE 1=0;
INSERT ALL
INTO StagingCustTable VALUES (1, 'aaa', 1, 1, 'AA', '111', 111.11, 1, 1 )
INTO StagingCustTable VALUES (3, 'ccc', 3, 3, 'CC', '333', 333.33, 3, 3 )
SELECT 1 FROM dual;
commit;
Now when you run this simple query:
SELECT 'SELECT ' || listagg( column_name, ',' ) WITHIN GROUP ( ORDER BY column_id )
|| chr(10) || ' FROM ' || max( table_name )
|| chr(10) || ' MINUS '
|| chr(10) || 'SELECT ' || listagg( column_name, ',' ) WITHIN GROUP ( ORDER BY column_id )
|| chr(10) || ' FROM StagingCustTable ' as MySql
FROM user_tab_columns
WHERE table_name = upper( 'CustomerTable' );
you will get the following result:
MYSQL
-------------------------------------------------------------------------
SELECT CUSTROMER_NUMBER,ADDRESS,ORDER_NUMBER,CONTACT,COUNTRY,POST_CODE,AMOUNT
FROM CUSTOMERTABLE
MINUS
SELECT CUSTROMER_NUMBER,ADDRESS,ORDER_NUMBER,CONTACT,COUNTRY,POST_CODE,AMOUNT
FROM StagingCustTable
Now just copy the above query, paste it to your SQL client, run it - and the task is done in a few minutes.

stored procedure parameter of CSV input to return all records

I have the following Oracle stored procedure that takes on a string of CSV of user ID's which would return the list of users to the output cursor which works fine:
create or replace PROCEDURE GET_USERS_BY_IDS
(
v_cur OUT sys_refcursor
,v_userIdsCsv IN varchar2 DEFAULT ''
) AS
BEGIN
open v_cur for
with userIds
as
(
select
trim( substr (txt,
instr (txt, ',', 1, level ) + 1,
instr (txt, ',', 1, level+1) - instr (txt, ',', 1, level) -1 ) )
as token
from (select ','||v_userIdsCsv||',' txt
from dual)
connect by level <=
length(v_userIdsCsv)-length(replace(v_userIdsCsv,',',''))+1
)
select
id
,lastname
,firstname
from
users
where
id in (select * from userIds);
END GET_USERS_BY_IDS;
so by doing exec GET_USERS_BY_IDS(:cur1, '123,456') I can get users of IDs of 123 and 456. However I would like to return ALL users if I pass in an empty string, i.e. exec GET_USERS_BY_IDS(:cur1, '') would return all users. What do I have to change in the sproc code to accomplish that? Thanks.
Consider this solution using REGEXP functions which I feel simplifies things. I also incorporated the test from my comment as well. Note the REGEXP handles a NULL list element too:
create or replace PROCEDURE GET_USERS_BY_IDS
(
v_cur OUT sys_refcursor
,v_userIdsCsv IN varchar2 DEFAULT '1'
) AS
BEGIN
open v_cur for
with userIds
as
(
select trim( regexp_substr(v_userIdsCsv, '(.*?)(,|$)', 1, level, NULL, 1) ) as token
from dual
connect by level <= regexp_count(v_userIdsCsv, ',') + 1
)
select
id
,lastname
,firstname
from
users
where v_userIdsCsv = '1' -- Empty list returns all users
OR id in (select * from userIds);
END GET_USERS_BY_IDS;
Its untested so let us know what happens if you test it.
Do you mean, something as simple as
BEGIN
if v_userIdsCsv = '' then
open v_cur for select id, lastname, firstname from users
else (rest of your code)
end if;
?
OK, with the confirmation in comments...
It seems you should be able to change the WHERE condition at the very end:
where
v_userIdsCsv = '' or id in (select * from userIds);
Outer join between user and user_ids. And clever where condition.
Has it helped?
with csv as (select '321,333' aa from dual)
,userIds
as
(
select
trim( substr (txt,
instr (txt, ',', 1, level ) + 1,
instr (txt, ',', 1, level+1) - instr (txt, ',', 1, level) -1 ) )
as token
from (select ','||(select aa from csv )||',' txt
from dual)
connect by level <=
length((select aa from csv ))-length(replace((select aa from csv),',',''))+1
)
select
user_id
,username
from
all_users a
left join userIds b on a.user_id = b.token
where nvl2((select aa from csv),b.token,a.user_id) = a.user_id
I think I found a more efficient way to do this now. In the where statement, I can just short-circuit it if the input parameter is a blank:
where
v_userIdsCsv = '' or
id in (select * from userIds);

Compare two schemas and update the old schema with the new columns of new schema

I've an Oracle database with two schemas. One is old and another is new. I would like to update the old schema with the new columns of the new schema.
I get the tables which have changes with the following query.
select distinct table_name
from
(
select table_name,column_name
from all_tab_cols
where owner = 'SCHEMA_1'
minus
select table_name,column_name
from all_tab_cols
where owner = 'SCHEMA_2'
)
With this query I get the tables. How can I update the old schema tables with the new columns? I don't need the data, just the columns.
A schema comparison tool is a good idea. The database schema is far more complicated than most people give credit, and every difference between two database schemas has the potential to cause bugs.
If you're still keen to do it yourself, the best approach I've found is to extract the schema definitions to text, then run a text compare. As long as everything is sorted alphabetically, you can then use Compare Documents feature in Microsoft Word (or FC.EXE, DIFF or equivalent), to highlight the differences.
The following SQLPlus script outputs the schema definition alphabetically, to allow comparison. There are two sections. The first section lists each column, in the format:
table_name.column_name: data_type = data_default <nullable>
The second section lists indexes and constraints, as follows:
PK constraint_name on table_name (pk_column_list)
FK constraint_name on table_name (fk_column_list)
CHECK constraint_name on table_name (constraint_definition)
The script serves as a useful references for extracting some of the Oracle schema details. This can be good knowledge to have when you're out at client sites and you don't have your usual tools available, or when security policies prevent you from accessing a client site database directly from your own PC.
set serveroutput on;
set serveroutput on size 1000000;
declare
rowcnt pls_integer := 0;
cursor c_column is
select table_name, column_name, data_type,
data_precision, data_length, data_scale,
data_default, nullable,
decode(data_scale, null, null, ',') scale_comma,
decode(default_length, null, null, '= ') default_equals
from all_tab_columns where owner = 'BCC'
order by table_name, column_name;
cursor c_constraint is
select c.table_name, c.constraint_name,
decode(c.constraint_type,
'P','PK',
'R','FK',
'C','CHECK',
c.constraint_type) constraint_type,
c.search_condition,
cc.column_1||cc.comma_2||cc.column_2||cc.comma_3||cc.column_3||cc.comma_4||cc.column_4||
cc.comma_5||cc.column_5||cc.comma_6||cc.column_6||cc.comma_7||cc.column_7 r_columns
from all_constraints c,
( select owner, table_name, constraint_name, nvl(max(position),0) max_position,
max( decode( position, 1, column_name, null ) ) column_1,
max( decode( position, 2, decode(column_name, null, null, ',' ), null ) ) comma_2,
max( decode( position, 2, column_name, null ) ) column_2,
max( decode( position, 3, decode(column_name, null, null, ',' ), null ) ) comma_3,
max( decode( position, 3, column_name, null ) ) column_3,
max( decode( position, 4, decode(column_name, null, null, ',' ), null ) ) comma_4,
max( decode( position, 4, column_name, null ) ) column_4,
max( decode( position, 5, decode(column_name, null, null, ',' ), null ) ) comma_5,
max( decode( position, 5, column_name, null ) ) column_5,
max( decode( position, 6, decode(column_name, null, null, ',' ), null ) ) comma_6,
max( decode( position, 6, column_name, null ) ) column_6,
max( decode( position, 7, decode(column_name, null, null, ',' ), null ) ) comma_7,
max( decode( position, 7, column_name, null ) ) column_7
from all_cons_columns
group by owner, table_name, constraint_name ) cc
where c.owner = 'BCC'
and c.generated != 'GENERATED NAME'
and cc.owner = c.owner
and cc.table_name = c.table_name
and cc.constraint_name = c.constraint_name
order by c.table_name,
decode(c.constraint_type,
'P','PK',
'R','FK',
'C','CHECK',
c.constraint_type) desc,
c.constraint_name;
begin
for c_columnRow in c_column loop
dbms_output.put_line(substr(c_columnRow.table_name||'.'||c_columnRow.column_name||': '||
c_columnRow.data_type||'('||
nvl(c_columnRow.data_precision, c_columnRow.data_length)||
c_columnRow.scale_comma||c_columnRow.data_scale||') '||
c_columnRow.default_equals||c_columnRow.data_default||
' <'||c_columnRow.nullable||'>',1,255));
rowcnt := rowcnt + 1;
end loop;
for c_constraintRow in c_constraint loop
dbms_output.put_line(substr(c_constraintRow.constraint_type||' '||c_constraintRow.constraint_name||' on '||
c_constraintRow.table_name||' ('||
c_constraintRow.search_condition||
c_constraintRow.r_columns||') ',1,255));
if length(c_constraintRow.constraint_type||' '||c_constraintRow.constraint_name||' on '||
c_constraintRow.table_name||' ('||
c_constraintRow.search_condition||
c_constraintRow.r_columns||') ') > 255 then
dbms_output.put_line('... '||substr(c_constraintRow.constraint_type||' '||c_constraintRow.constraint_name||' on '||
c_constraintRow.table_name||' ('||
c_constraintRow.search_condition||
c_constraintRow.r_columns||') ',256,251));
end if;
rowcnt := rowcnt + 1;
end loop;
end;
/
Unfortunately, there are a few limitations:
Embedded carriage returns and whitespace in data_defaults, and check constraint definitions, may be highlighted as differences, even though they have zero effect on the schema.
Does not include alternate keys, unique indexes or performance indexes. This would require a third SELECT statement in the script, referencing all_ind_columns and all_indexes catalog views.
Does not include security details, synonyms, packages, triggers, etc. Packages and triggers would be best compared using an approach similar to the one you originally proposed. Other aspects of the schema definition could be added to the above script.
The FK definitions above identify the referencing foreign key columns, but not the PK or the table being referenced. Just one more detail I never got around to doing.
Even if you don't use the script. There's a certain techie pleasure in playing with this stuff. ;-)
Matthew
I'm afraid I can't do more for you at the moment, but this should give you a basic idea.
It selects ADD and DROP column statements that you could execute after carefully reviewing them.
It does not handle
created/dropped tables
data type/precision changes of existing columns (ALTER TABLE MODIFY)
DEFAULT VALUES (so you can't apply it on a table with data when new column is NOT NULL)
Check constraints, Foreign Key constraints
I tried it with some basic data-types (NUMBER, VARCHAR2, DATE) and it worked. Good luck :)
SELECT 'ALTER TABLE ' || LOWER(table_name)
|| ' ADD ' || LOWER(column_name) || ' ' || data_type
|| CASE WHEN data_type NOT IN ('DATE') THEN '(' || data_length || ')' END
|| CASE WHEN nullable='Y' THEN ' NOT NULL' END
|| ';' cmd
FROM all_tab_cols c2
WHERE owner = 'SCHEMA_1'
AND NOT EXISTS ( SELECT 1
FROM all_tab_cols c1
WHERE owner = 'SCHEMA_2'
AND c1.table_name = c2.table_name
AND c1.column_name = c2.column_name )
UNION ALL
SELECT 'ALTER TABLE ' || LOWER(table_name)
|| ' DROP COLUMN ' || LOWER(column_name) || ';'
FROM all_tab_cols c2
WHERE owner = 'SCHEMA_2'
AND NOT EXISTS ( SELECT 1
FROM all_tab_cols c1
WHERE owner = 'SCHEMA_1'
AND c1.table_name = c2.table_name
AND c1.column_name = c2.column_name )
ORDER BY cmd;
I started writing an answer for this but my list of caveats became longer than the answer so I decided to scrap it.
You should go for a schema comparison tool.
There are free versions available - take a look at this question on Server Fault:
https://serverfault.com/questions/26360/how-can-i-diff-two-oracle-10g-schemas
My suggestion would be to download Oracle's SQL Developer and use the built-in schema diff tool (although this requires that you have the Change Management Pack license).

Resources