Wednesday, August 26, 2009

Using other users' schemas as our own

As a DBA (A for Administrator or Architect), some times you'll be required to create, edit, drop or test schema objects of users of the database.

As you want to keep your DBA rights and don't want to bother creating new connections (on GUI clients) or just don't want to close your current session con SQL*Plus and due to the fact that is a pain in the back to write every schema object with the schema name in front of it... You may consider setting your default schema for the current session to the one of the user that requires your assistance.

How? It's really easy, you can simpy execute a query to ALTER your own session and point it to another schema. That's done as follows:

ALTER SESSION SET CURRENT_SCHEMA = the_schema_you_want_to_use

This will make all of your queries over that new schema as if you were its owner, of course maintaining your privileges as DBA.

More so, you may have groups of users that should work over the same schema, you can assign a role and then implement a trigger to alter the session when they log on, with a trigger that should look like this (not tested yet):

CREATE OR REPLACE TRIGGER set_default_schema
AFTER LOGON ON DATABASE WHEN (USER = 'XYZ')
BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION SET CURRENT_SCHEMA = ABC';
END;

It can be even be modified to see if (USER IN (SELECT... FROM... WHERE...)) so you can get groups of users pointing at the same schema as soon as they login.

Friday, August 21, 2009

Drop that unknown NOT NULL constraint - Part 2

Recently I got word from someone at a Database Forum pointing that it would be easier to join a couple tables to get the name of the constraint we want to drop.

The code is this:

SELECT c.constraint_name
FROM user_tab_columns t, user_cons_columns c
WHERE t.table_name = my_table
AND t.table_name = c.table_name
AND t.column_name = my_column
AND t.nullable = 'N';
That's it, we got now the constraint name and can drop it easely.

That would shorten the script a lot, tho the performance will probably depend on various details as the number of rows per table and the position of the value we look up.

So, the new script would look as follows:

DECLARE
constname user_cons_columns.constraint_name%TYPE;
BEGIN
SELECT c.constraint_name INTO constname
FROM user_tab_columns t, user_cons_columns c
WHERE t.table_name = my_table
AND t.table_name = c.table_name
AND t.column_name = my_column
AND t.nullable = 'N';

EXECUTE IMMEDIATE 'ALTER TABLE my_table DROP CONSTRAINT ' || 'constname';
dbms_output.put_line('Constraint '|| constname || ' dropped successfuly!');
COMMIT;
END;
Nevertheless and despite the obvious change in the size and performance of this script, during the test, I found something interesting: it fails if the constraint is disabled, due to the fact that user_tab_columns.nullable contains the current value of the system itself and not the one from the constraint.

Thursday, August 20, 2009

Oracle Error Codes - A nightmare? Not anymore!

Yes, usually we're working with a DB and all of the sudden an ORA-XXXXX error rises without a lot more info than the error code itself...

So you have to go Google-it, start looking in forums, blogs and all sort of strange net-places if not books to find what the... base does that error code mean...

Well, this is the shortest post I'll probably write here.

Just enter go to http://*error-code-here*.ora-code.com/

That means that if you're looking for the error code ora-00997, you must go to

http://ora-00997.ora-code.com

Enjoy!

And big thanks to people behind that site!
http://any-code.ora-code.com

Drop that unknown NOT NULL constraint - Part 1

Is very natural for any DBA to create tables through the ol' good DDL statement:

CREATE TABLE sysuser (
login VARCHAR2(20) PRIMARY KEY,
pswd VARCHAR2(20) NOT NULL
);

But that generates later problems because the DBMS will name those constraints as "SYSXXXXX", as I have discovered recently in my job. Some, will instantly say:
-Hey, wait. For that PK I use the ALTER TABLE statement and add a name like "PK_sysuser" to the constraint for better understanding of later raisen errors.

Well, yes. That's right, but we almost never take the time to add custom names to NOT NULL constraints. That's exactly the problem here.

Some time ago, a table was created (in development environment and later on in production), with its constraints and everything was fine until yesterday. A developer came to me, asking if it's posible to drop that constraint "automatically" since we don't have access to the production environment. The answer was clear, if it exists... It can be dropped. More so, the Data Dictionary got all the necesary information to do it. So it should be a quick and easy task to accomplish.

What I got:
  • Table & field names
What I need:
  • Find the name of the constraint
  • Drop the constraint

I first used:

SELECT *
FROM user_constraints
WHERE table_name =
my_table;


Got a bunch of data and got the search_condition of the constraint as "my_field" IS NOT NULL. And I thought - Job done! All I have to do is refine my query to use this field and I'll get the name of the constraint I want to drop; so it would be a simple PL/SQL block of about a half dozen lines.

So my fingers ran through the keyboard writing:

SELECT constraint_name
FROM user_constraints
WHERE search_condition = '"my_field" IS NOT NULL';


- AHA!!! Oracle error: ORA-00997!!!

So I googled a bit and found that LONG (datatype) fields can't be used in WHERE clauses!!
And, as Murphy's Laws dictates, search_condition is a LONG field.

To shorten this up, I'll say that I took some workarounds and finished creating this script:

SET SERVEROUTPUT ON;

DECLARE
aux user_constraints.search_condition%TYPE;
condition user_constraints.search_condition%TYPE;
constname user_constraints.constraint_name%TYPE;
CURSOR names IS
SELECT constraint_name
FROM user_constraints
WHERE table_name LIKE 'my_table'
AND constraint_type = 'C';
CURSOR search IS
SELECT search_condition
FROM user_constraints
WHERE table_name LIKE 'my_table'
AND constraint_type = 'C';
BEGIN
OPEN names;
OPEN search;

condition:= '"my_field" IS NOT NULL';
dbms_output.put_line('Contrained column is: my_field');

LOOP
FETCH names INTO constname;
FETCH search INTO aux;

dbms_output.put_line('Constraint name is: '||constname);
dbms_output.put_line('Search condition is: '|| aux);

IF aux = condition THEN
dbms_output.put_line('Selected constraint to drop: '|| constname);
END IF;

EXIT WHEN aux = condition;
END LOOP;

CLOSE names;
CLOSE search;
EXECUTE IMMEDIATE ('ALTER TABLE my_table DROP CONSTRAINT ' || constname);
COMMIT;
dbms_output.put_line('Constraint dropped succesfully');

END;

I hope this helps some of you, and I'm not stating here this is the best way to do it. It's just one way to do it. I even created a Stored procedure with table_name and column_name as INPUT parameters that will drop any "unknown" NOT NULL constraint from any table and any field.

All comments are welcome!