From this blog you can try this on development first...
SQL> spool resolve.sql;
SQL> select ‘alter java class “‘||object_name||’” resolve;’
2 from user_objects
3 where object_type like ‘%JAVA%’;
SQL> spool off;
SQL> @resolve
The clean sweep approach would be to remove and reinstall the java JVM
The Java VM is created and populated with system classes during CREATE OR REPLACE JAVA SYSTEM command. Run rmjvm.sql to remove the JVM first, then bounce the database then initjvm.sql
I repeat, these should be tried on your development stack first!
The problem with your first example is the tri-link table. Is that going to require one of the foreign keys on either report or recommendations to always be NULL so that keywords link only one way or the other?
In the case of your second example, the joining from the base to the derived tables now may require use of the type selector or LEFT JOINs depending on how you do it.
Given that, why not just make it explicit and eliminate all the NULLs and LEFT JOINs?
Reports
----------
ReportID
ReportName
Recommendations
----------
RecommendationID
RecommendationName
ReportID (foreign key)
Keywords
----------
KeywordID
KeywordName
ReportKeywords
----------
KeywordID (foreign key)
ReportID (foreign key)
RecommendationKeywords
----------
KeywordID (foreign key)
RecommendationID (foreign key)
In this scenario when you add something else which needs to be tagged, you just add the entity table and the linkage table.
Then your search results look like this (see there is still type selection going on and turning them into generics at the object results level if you want a single results list):
SELECT CAST('REPORT' AS VARCHAR(15)) AS ResultType
,Reports.ReportID AS ObjectID
,Reports.ReportName AS ObjectName
FROM Keywords
INNER JOIN ReportKeywords
ON ReportKeywords.KeywordID = Keywords.KeywordID
INNER JOIN Reports
ON Reports.ReportID = ReportKeywords.ReportID
WHERE Keywords.KeywordName LIKE '%' + @SearchCriteria + '%'
UNION ALL
SELECT 'RECOMMENDATION' AS ResultType
,Recommendations.RecommendationID AS ObjectID
,Recommendations.RecommendationName AS ObjectName
FROM Keywords
INNER JOIN RecommendationKeywords
ON RecommendationKeywords.KeywordID = Keywords.KeywordID
INNER JOIN Recommendations
ON Recommendations.RecommendationID = RecommendationKeywords.ReportID
WHERE Keywords.KeywordName LIKE '%' + @SearchCriteria + '%'
No matter what, somewhere there is going to be type selection and some kind of branching going on.
If you look at how you would do this in your option 1, it's similar but with either a CASE statement or LEFT JOINs and a COALESCE. As you expand your option 2 with more things being linked, you have to keep adding more LEFT JOINs where things are typically NOT being found (an object that is linked can only have one derived table which is valid).
I don't think there is anything fundamentally wrong with your option 2, and you could actually make it look like this proposal with a use of views.
In your option 1, I have some difficulty seeing why you opted for the tri-link table.
Best Answer
The trick is get the packages and dependent code recompiled in one go. If you are refreshing a development database with new data you will have an enormous list of invalid procedures. As well, with dependent code you find yourself recompiling over and over. You can use this command located in $ORACLE_HOME/rdbms/admin/utlrcmp.sql:
(available from 9i but improved for 10g and 11)
If you have packages that are not valid and will not be valid, for whatever reason, you can use this package from Martin Mares which will recursively compile all invalid objects except the ones you specify.
As far as best practice goes I try to limit the dependency chain. It's always a toss up between "Don't repeat yourself" which encourages dependencies and having stand alone packages.
My rule of thumb is that if the package/trigger/object interacts with another database try to reduce dependencies so if there is a issue you have less places to look for sources of the problem.