Friday, October 31, 2008

Run a SQL Query from DOS

This is a DOS batch file that will be run at the DOS prompt. You must supply the user, password, and the SQL query name you wish to run. For example:

Since the SQL query must have an 'EXIT' statement at the end, I've actually had this batch file call a two-line query that calls the query you requested, and then exits. This batch file assumes that all your code is in a directory called 'Data', and that the output of your query can be displayed in Notepad, and that the spool file name matches the query name with an 'TXT' extension.

SqlFromDos.Bat
Rem -+---------------------------------------
Rem -| Turn off the display
Rem -+---------------------------------------

@Echo Off

Rem -+---------------------------------------
Rem -| Pick up the variables typed
Rem -| i.e., SqlFromDos Scott Tiger Emptest
Rem -+---------------------------------------

Set User=%1
Set Pass=%2
Set Query=%3

Rem -+---------------------------------------
Rem -| Apply the variables to the login
Rem -+---------------------------------------

Sqlplus %User%/%Pass% @C:\Data\RunFromDos %Query%

Rem -+---------------------------------------
Rem -| When SQL*Plus is done, return to
Rem -| DOS, clear the screen, and open
Rem -| Notepad to view the report
Rem -+---------------------------------------

cls
Notepad C:\Data\%Query%.txt

This is called by SqlFromDos.Bat;


RunFromDos.Sql
@&1
Exit

This is called by RunFromDos.Sql:


EmpTest.Sql
Set Echo Off Linesize 200 Pagesize 60 Trimspool On
Spool Emptest.Txt
Select *
From Emp;
Spool Off

Saturday, October 25, 2008

Execute Immediate: Count Rows in All Tables

The EXECUTE IMMEDIATE statement allows you to build a statement on-the-fly. This is useful if you don't know the name of a table or the where conditions in advance. In this case, we'll get each table name in the schema and then ask for a count. Since this list will vary from time to time, the Execute Immediate makes sure we get a complete list.
Clear Screen
Prompt This will display the record count for all the tables in a schema.
Prompt Note: This does not display external tables, global temporary tables or tables in the recycle bin.
Prompt ------

Accept Schema Prompt 'Please type schema name: '
Prompt

Set Echo Off
Set Serveroutput On Verify Off

Declare
v_Stmt Varchar2(4000) ;
v_Num_Rows Number ;

Begin
Dbms_Output.Enable(1000000) ;

For Rec In
(
Select Owner, Table_Name
From DBA_Tables dt
Where Owner=Upper('&Schema')
And Table_Name Not Like 'BIN%' /* not in recycle bin */
And Not Exists (Select '1' /* not an external table */
From DBA_External_Tables det
Where dt.Table_Name = det.Table_Name
)
And Temporary = 'N' /* Not a temporary table */
Order by Table_Name
)

Loop
v_Stmt:= 'Select Count(1)' ||
'From ' || Rec.Owner || '.' || Rec.Table_Name ;

Execute Immediate v_Stmt Into v_Num_Rows;

Dbms_Output.Put_Line('# Rows: '||
To_Char(v_Num_Rows,'999,999')
||' - '||
Rec.Table_Name
);
End Loop;
End;
/
Thanks to Rob Balter, DBA at MSA for the core logic.
See Oracle Online Documentation for further detail:
Execute Immediate

Friday, October 24, 2008

HR Tables: Keys Used in Joins

Column Countries   Format A15
Column Departments Format A15
Column Employees Format A15
Column Jobs Format A15
Column Job_History Format A15
Column Locations Format A15
Column Regions Format A15

Set Markup Html On Entmap On Spool On Preformat Off
Set Term Off

Spool Fk.Htm

Set Heading Off
Column Title Entmap Off
Select '<Center><H1>Hr Tables : Keys Used In Joins</H1></Center>' As Title
From Dual;

Set Heading On
Select Max(Case When Table_Name = 'EMPLOYEES' Then Column_Name End) As EMPLOYEES,
Max(Case When Table_Name = 'JOBS' Then Column_Name End) As JOBS,
Max(Case When Table_Name = 'JOB_HISTORY' Then Column_Name End) As JOB_HISTORY,
Max(Case When Table_Name = 'DEPARTMENTS' Then Column_Name End) As DEPARTMENTS,
Max(Case When Table_Name = 'LOCATIONS' Then Column_Name End) As LOCATIONS,
Max(Case When Table_Name = 'COUNTRIES' Then Column_Name End) As COUNTRIES,
Max(Case When Table_Name = 'REGIONS' Then Column_Name End) As REGIONS
From (
Select *
From (
Select Table_name, Initcap(Column_name) Column_name ,
Count(*) Over (Partition By Column_name
Order By Column_name) Colctr
From User_tab_columns
Where Table_name not in ( 'TEST' , 'EMP_DETAILS_VIEW')
)
where Colctr <> 1
)
Group By Column_name
Order By Column_name;

Spool Off

Set Markup Html Off Entmap Off Spool Off Preformat Off
Set Term On

PROMPT ** Report Completed. Use Mozilla to view your output: FK.HTM **

Finding Discrepancies in Column Definitions

When setting up tables in a schema, you may want to assure that your column definitions are the same as those already defined.

This query will count how many times each column is found, and how many unique variations there are in the type and length. If the counts are identical, they are omitted from the report.

In the above example, there are three fields named 'CATEGORY'; a length of 20 was used twice, and a length of 10 was used once.
Break On Column_Name Dup Skip 1

Column Data_Length Format A6
Column CntDif Format 999 Heading Type/|Length|Count
Column CntAll Format 999 Heading Column|Name|Count

Select CntAll, Column_Name, Data_Type,
Data_Length, CntDif, Table_Name
From
/*-------------------------------------------------------------------------*/
(
Select Column_Name,
Table_Name,
Data_Type,
------------------------------------------------------
Case When Data_Precision Is Not Null
Then Data_Precision||'.'||Data_Scale
Else To_Char(Data_Length)
End As
Data_Length,
------------------------------------------------------
Count(*) Over (Partition By Column_Name
Order By Column_Name)
As
CntAll,
------------------------------------------------------
Count(*) Over (Partition By Column_Name, Data_Type,
Data_Length, Data_Precision,
Data_Scale
Order By Column_Name)
As
CntDif
------------------------------------------------------
From User_Tab_Columns
Where Table_Name Not Like 'BIN%'
)
/*-------------------------------------------------------------------------*/
Where CntAll <> CntDif
Order By Column_Name, CntAll, Data_Type,
Data_Length, CntDif, Table_Name;

Wednesday, October 22, 2008

Reserved Words

[A]
All
Alter
And
Any
As
Asc

[B]
Between
By

[C]
Char
Check
Cluster
Compress
Connect
Create
[D]
Date
Decimal
Default
Delete
Desc
Distinct
Drop

[E]
Else
Exclusive
Exists

[F]
Float
For
From

[G]
Grant
Group

[H]
Having

[I]
Identified
In
Index
Insert
Integer
Intersect
Into
Is



[L]
Like
Lock
Long

[M]
Minus
Mode

[N]
Nocompress
Not
Nowait
Null
Number




[O]
Of
On
Option
Or
Order

[P]
Pctfree
Prior
Public

[R]
Raw
Rename
Resource
Revoke


[S]
Select
Set
Share
Size
Smallint
Start
Synonym

[T]
Table
Then
To
Trigger





[U]
Union
Unique
Update

[V]
Values
Varchar
Varchar2
View

[W]
Where
With






This is a list of all the reserved words in v$Reserved_Words. The above report was generated as one long list. I took it into a word processor to put it in columns.

To get a heading like '[A]':
  • Use a 'Prompt' for your title
  • Use TTitle for your subtitle.
  • Substring to get the first character.
  • Break on that first character and skip a page
  • Use the variable created with the New_Value in the title, but do not put in the ampersand.
Break On Char1 Skip Page
Prompt Reserved Words
Ttitle Left '[' TitleChar ']'
Set Heading Off
Column Char1 New_Value TitleChar

Select Substr(Keyword,1,1) Char1,
Initcap(Keyword)
From V$Reserved_Words
Where Reserved = 'Y'
And Substr(Keyword,1,1) Between 'A' And 'Z'
Order By Char1, Keyword;

Display a Calendar and Prompt for a Date

The code for the calendar procedure was found on OTN and was created by Pablo Rovedo, DBA at ADEA S.A., in Buenos Aires, Argentina.

My script gets the current month and year, and passes it to the procedure. I then prompt the user for the day of the month. The goal of this is to run a report based on a date. If the users picks something later than the Sysdate, they are prompted with an error message (but the script doesn't really stop.)

In the above picture, the script is run twice. The first time, a report is returned; the second, an error message.

This is the test table I created:
Create Table Test
(Person Varchar2(10)
,Testdate Date
);
Insert Into Test Values('Diane' ,Sysdate-2);
Insert Into Test Values('Lynn' ,Sysdate-3);
Insert Into Test Values('Craig' ,Sysdate-4);
Insert Into Test Values('Denise',Sysdate-5);
Insert Into Test Values('Glenn' ,Sysdate-6);
Insert Into Test Values('Jacque',Sysdate-7);

The script:
--------------------------------------------------------------------
-- Get month and year to display this month's calendar
--------------------------------------------------------------------
Set Term Off Serveroutput On Verify Off
Column mm New_Value mm
Column yyyy New_Value yyyy

Select To_Char(Sysdate,'mm' ) mm,
To_Char(Sysdate,'yyyy') yyyy
From Dual;
Set Term On

exec calendar ('&mm','&yyyy');

--------------------------------------------------------------------
-- Explain the purpose of report and Get the day of month
--------------------------------------------------------------------

Prompt
Prompt This report displays records for a day.
Accept DOM Number Prompt 'Please choose the day: '

--------------------------------------------------------------------
-- DOM needs to be trimmed since it was defined as 'Number' in the
-- Accept statement.
-- Use case to set up for possible error msg. The prompt will either
-- display a message or it will display nothing
--------------------------------------------------------------------

Set Term Off
Column DateError New_Value DateError
Column Test_DOM New_Value Test_DOM

Select Ltrim(&DOM,' ') Test_DOM,
Case When &DOM > To_Char(Sysdate,'dd')
Then 'Error: Day must be today or before.'
Else ' '
End
As DateError
From Dual;

Set Term On
Prompt &DateError

--------------------------------------------------------------------
-- Select everything from our test table where the date matches the
-- date we put together. The table date will have to be
-- truncated to remove any time, and get a match
--------------------------------------------------------------------

Select *
From Test
Where To_Date('&Test_Dom'||'-'||'&mm'||'-'||'&yyyy','dd-mm-yyyy')
= Trunc(Testdate);

Schema Space Consumption

Set Pagesize 100
Column GB Format 99.99
Column Owner Format A30
Break on Report
Compute Sum of GB on Report

Select RPad(Owner,30,' .')
As
Owner,
-------------------------------------------------------
Round ( Sum(Sum_Bytes) / 1024 / 1024 / 1024, 2 )
As
Gb
From
--+----------------------------------------------------
(
Select Owner,
--------------------
Sum(Bytes)
As
Sum_Bytes
--------------------
From Dba_Segments ds
Where Exists (
Select Username
From Dba_Users du
Where du.Username = ds.Owner
)
Group By Owner
, Segment_Name
, Segment_Type
)
--+----------------------------------------------------
Group By Owner
Order By GB Desc;

Tuesday, October 21, 2008

An Example of Ansi Joins with Multiple Tables

These tables are from the HR schema. I'm showing two examples, one uses 'Using' and the other with the 'On.'
         Select r.Region_Name
, c.Country_Name
, l.State_Province
, d.Department_Name
, e.Last_Name
, e.Job_Id
From Regions R
Join Countries C On r.Region_Id = c.Region_Id
Full Outer Join Locations L On c.Country_Id = l.Country_Id
Full Outer Join Departments D On l.Location_Id = d.Location_Id
Full Outer Join Employees E On d.Department_Id = e.Department_Id
Where r.Region_Name = 'Americas'
And c.Country_Name <> 'United States of America';
Select r.Region_Name
, c.Country_Name
, l.State_Province
, d.Department_Name
, e.Last_Name
, e.Job_Id
From Regions R
Join Countries C using ( Region_Id )
Full Outer Join Locations L using ( Country_Id )
Full Outer Join Departments D using ( Location_Id )
Full Outer Join Employees E using ( Department_Id )
Where r.Region_Name = 'Americas'
And c.Country_Name <> 'United States of America';

List All Constraints in a Schema

This report was modified so it could fit in this blog.


The actual code can be found on my web site as an attachment: UserCons.Sql

Show the Percentage of Records that Meet a Criteria

Select Round(Part/Whole*100,1)||'%' Percentage
From
(Select Count(*) Whole From Emp ),
(Select Count(*) Part From Emp Where Deptno = 30);

Percentage
----------
42.9%

Where: How to Search for Various Conditions

This query presents the operator with a choice of how to find data. After selecting a search field, and entering a value, a decode is used to generate SQL code. The New_Value clause sets that equal to &xWhere, and it is used with the 'Where' clause.

(I have tried incorporating it directly into the Where with no luck.)
Prompt
Prompt +------------------------------------------+
Accept Choice Prompt '| Search by 1-EmpNo 2-EName : '
Accept Value Prompt '| Please enter Value : '
Prompt +------------------------------------------+

Set Term Off
Column WhereClause New_Value xWhere
Select Decode(&Choice, 1, 'EmpNo=&Value',
2, 'EName='||Upper('''&Value''')
)
As
WhereClause
From Dual;
Set Term On

Select EmpNo, EName, Job, HireDate, DeptNo
From Emp
Where &xWhere;

Data Samples

SAMPLE [ BLOCK ] (sample_percent)  [ SEED (seed_value) ]
See the Select statement in the Oracle® SQL Reference for exceptions, refinements, and cautions regarding 'Block', 'Seed', etc.
SQL> Select Count(*) From Employees;

COUNT(*)
----------
107

1 Select Employee_Id, First_Name, Last_Name
2* From Employees Sample(10);

EMPLOYEE_ID FIRST_NAME LAST_NAME
----------- -------------------- --------------
109 Daniel Faviet
112 Jose Manuel Urman
118 Guy Himuro
119 Karen Colmenares
128 Steven Markle
136 Hazel Philtanker
148 Gerald Cambrault
170 Tayler Fox
Since this is just an estimate, unless you specify a 'seed,' you will get a variation of counts returned:
  1* Select Count(*) From Employees Sample(10)
SQL> /
15
SQL> /
10
SQL> /
11
SQL> /
10
SQL> /
9

Delete Duplicate Records


This logic was found on PL/SQL Pipeline:
To test, insert a duplicate 'SMITH' on the EMP TABLE:
Insert Into Emp Values(9999,'SMITH','CLERK',7902,'17-DEC-80',800,NULL,20);
Commit;
You can see what is happening in the above report, and how a record is being chosen for deletion by running the following query. Records are being ranked (and a RowId saved) by breaking all the employees into partitions based on their name, hire date, and department. Within each 'partition,' they are ordered by the Rowid.
Select Rowid, Empno, EName, HireDate, Deptno,
Rank() Over (Partition By EName, HireDate, DeptNo
Order By Rowid)
As
Ranking
From Emp;

This sets us up the delete:
Delete From Emp 
Where Rowid In
( Select Rowid
From
( Select Rowid,
Rank() Over (Partition By EName, HireDate, DeptNo
Order By Rowid)
As
Ranking
From Emp
)
Where Ranking > 1
);

Case vs. Decode


The DECODE and CASE statements can generate the same report as shown on the right. The Case statement (which has two variations) is newer and has several advantages over the Decode.
  • offers more flexibility and logical power (see Case Examples)
  • easier to read than DECODE
  • offers better performance as well

DECODE(value,if1,then1[,if2,then2,]...,else)
  • value can be any column or the result of a computation, a substring, etc.
Select Grade,
Decode(Grade,2 , 'Needs a Raise' ,
3 , 'Average Pay' ,
4 , 'Almost There' ,
5 , 'Upper Echelon' , '?')
As
Grade_Desc
From SalGrade;


CASE WHEN condition_1 THEN result_1
WHEN condition_2 THEN result_2
...
ELSE else_result
END

Select Ename, Grade,
CASE WHEN Grade = 2 THEN 'Needs a Raise'
WHEN Grade = 3 THEN 'Average Pay'
WHEN Grade = 4 THEN 'Almost There'
WHEN EName = 'KING' Then 'King of the Hill'
WHEN Grade = 5 THEN 'Upper Echelon'
ELSE '?'
END
Grade_Desc
From SalGrade , Emp
Where Sal Between LoSal and HiSal
/

- OR -
CASE expression WHEN value_1 THEN result_1
WHEN value_2 THEN result_2
...
ELSE else_result
END


Select Grade,
CASE Grade When 2 THEN 'Needs a Raise'
When 3 THEN 'Average Pay'
When 4 THEN 'Almost There'
When 5 THEN 'Upper Echelon'
ELSE '?'
END
Grade_Desc
From SalGrade;

Oracle User and Schema

Who am I?
SQL> Select Instance_Name From v$Instance;

INSTANCE_NAME
----------------
orcl10

SQL> Select Name From v$Database;

NAME
---------
ORCL10

SQL> Select User From Dual;

USER
------------------------------
SCOTT

Monday, October 20, 2008

Nullif


The NullIf statement compares one value with another. If they match, it returns null, otherwise it returns the first. In this example, the NullIf, and the following Case statement get the same results.
Column Employee_Id  Heading Employee|Id
Column NullIf_JobId Heading NullIf|(E_Job_Id)
Column Case_JobID Heading Case|(E_Job_Id)
Column Equals Heading '='
Column E_Job_Id Heading E.|Job_id
Column J_Job_Id Heading J.|Job_id

Select E.Employee_Id,
E.Job_Id As E_Job_Id,
--------------------------------------------
Case When E.Job_Id = J.Job_Id
Then '='
Else ' '
End
As
Equals,
--------------------------------------------
J.Job_Id As J_Job_Id,
--------------------------------------------
Nullif(E.Job_Id, J.Job_Id) /* this is the same as the following case */
As
NullIf_JobId,

--------------------------------------------
Case When E.Job_Id = J.Job_Id /* this is the same as the nullif */
Then Null
Else E.Job_ID
End
As
Case_JobID

--------------------------------------------
From Employees E,
Job_History J
Where E.Employee_Id = J.Employee_Id
Order By E.Employee_Id;

Find Discrepancies with 'Distinct Count Over'

In this query, I'm looking for discrepancies in data. In particular, I want to find column names in the data dictionary which have more than one type of data assigned. This is done by asking for a distinct count of data_types within a partition based on column_names. The code then eliminates anything that has a count of one.
Select *
From
(
Select Table_Name,
Column_Name,
Data_Type,
Count(Distinct Data_Type)
Over(Partition By Column_Name)
As
Cnt
From All_Tab_Columns
Where Table_Name Like 'USER_%'
)
Where Cnt >1
Order By Column_Name;

Using Colors and Fonts in HTML Reports


This is absolutely a sign of a person with too much time on their hands! Colors & fonts? Who knows where this will lead. Anyway, I usually use <H1> to indicate a title, but you can't if you want to set size, color or face; it will override these.

There are many internet sites that give a list of all the colors, faces and sizes so I'm not going to list them here again. I did want to make a note of how they worked in the code. Again, for any column that will have HTML codes in it, you must define with 'Entmap Off.'

I also highlighted the president's position by using a case statement.

(The title was broken onto 4 lines and concatenated simply to list in this blog. Initially, it was one record.)
Set Term Off Echo Off Heading Off Linesize 2000 Feedback Off
Set Markup Html On Entmap On Spool On Preformat Off

Column Title Entmap Off
Column Ename Entmap Off Format A100 Heading EName|Job
Column Sal Format 9,999

Spool Test.Html
Column User New_Value xSchema Noprint
Column Rundate New_Value xRundate Noprint
Column Name New_Value xDatabase Noprint

Select '<Font Size=7><Font Color = "#FF0000"><Font Face ="Amazone BT">'
||'<Center>Names, Jobs and Salaries</Center>'
||'<Center><H2>(President is shown in red)'
||'</H2></Center></Font><Font Color = Ff0000>'
Title,
-------------------------------------------------------------------------
User,
Name,
-------------------------------------------------------------------------
To_Char(Sysdate,'fmMonth Dd, Yyyy Day')
||To_Char(Sysdate,' Hh24:Mi')
As
Rundate
-------------------------------------------------------------------------
From V$Database;

Prompt Run Date : &xRunDate
Prompt Output : Test.Html
Prompt Schema : &xSchema @ &xDatabase

Set Heading On

Select Empno,
Case When Job = 'PRESIDENT'
Then '<Font Color = "#Ff0000"><B>'
||Ename
||',<br>'
||Job
||'<Font Color = Ff0000></B>'
Else Ename
||',<br>'
||Job
End
As
Ename,
Sal,
Deptno
From Emp;

Spool Off
Set Markup Html Off Entmap Off Spool Off Preformat Off
Set Echo On Term On

Connect By Displayed as HTML


The Connect By displays the hierarchy of data. To generate the above report, we've indented the name by padding with three spaces for each level deep it is. Since we don't want to pad the 1st level, subtracting one puts it in the right place.
Select Empno,
Lpad(' '          -- Print a space
,3*(Level-1)  -- Pad with spaces for 3 times one less than the level
)  ||  Ename  -- Join spaces with the name to show hierarchy
As
EmpNm,
Mgr
From Emp
Start With Ename = 'KING'
Connect By Mgr = Prior Empno
Order Siblings By Ename;
If you wish to accomplish the same thing, but want to display it in a browser, Word or Excel, you'll need to make a few adjustments.
  • For one thing, a space is virtually undetectable, so you'll want to increase the amount of space by quite a bit.
  • A space has to be written as '&nbsp;', and since the ampersand is a variable to SQL, you need to add 'Set Escape On', and put a backslash ('\') in front of the ampersand.
  • Setting 'Term Off' always helps since it just takes up time to watch HTML scroll by.
  • The column that contains the escape character must be defined with 'Entmap Off', and must be long enough to contain all the 'nbsp;'s that you'll be adding without it wrapping to a second line. For instance, if the name is only formatted for 10 characters then the output would look like this:
  • EMPNO  EMPNM             MGR
    ------ ---------- ----------
    7698   &nbsp;&nbs       7839
    p;BLAKE
    At least for Blake, we need a length of 17 (6+6+5).
  • Use an extension of 'HTML' for a browser to automatically read the spool file; 'DOC' for Word; 'XLS' for Excel, etc.
  • The length of the pad (in this case, 24) must be a multiple of six as there are six characters in '&nbsp;' and anything else will occasionally give you only parts of that code.
  • The second expression in an LPAD is a default of space, but remember in the spooled file '   ' and '&nbsp; are different.

Other than that, there's nothing to it! :o)
SET MARKUP HTML ON ENTMAP ON SPOOL ON PREFORMAT OFF
Set Term Off
Set Escape On

Column Empnm Format A100 Entmap Off
Spool htmltest.html

Select Empno,
Lpad ('\&nbsp;'     -- pad with spaces
,(Level-1)*24  -- the length of the pad is based on the level
,'\&nbsp;'     -- fill in with this (default is space, but that's different)
)||Ename 
As 
Empnm,
Mgr
From Emp
Start With Ename = 'KING'
Connect By Mgr = Prior Empno
Order Siblings By Ename;

SET MARKUP HTML OFF ENTMAP OFF SPOOL OFF PREFORMAT OFF
Spool Off
Set Term On

A Way to Resolve a Lock Conflict


The following code generates two lines. The first is a prompt to say what is going to happen, and the second is a 'KILL SESSION' statement.

Which session needs to be killed is determined by the Blocking_Session from V$Session. This query does not actually run that line -- it just generates it. After running this, the DBA can copy and paste the line as shown on the screen, or run KL.SQL to kill the session.
rem +--------------------------------------------------------------------------+
rem | Script ID: KillLock.sql
rem | Purpose: Resolve Lock Conflicts
rem |
rem | Developer: Lynn Tobias
rem | Script Date: September 23, 2008
rem | Oracle Ver: 10g
rem |
rem | Table(s) Used: V$Session
rem | Output: KL.SQL
rem +--------------------------------------------------------------------------+
Set Echo Off
Set Heading Off Linesize 300 Feedback Off
Column Line Format A300
--------------------------------------------------------------------------------
-- Display the line and build a sql file that looks like:
-- -- SCOTT's session will be killed
-- Alter System Kill Session '140,2540' Immediate;
--
-- Note: Cut and paste, or type '@KL' to run.
--------------------------------------------------------------------------------
Spool KL.Sql

Select '-- '||Username||'''s session will be killed'
|| chr(10)
|| 'Alter System Kill Session '''||Sid||','||Serial#||''' Immediate;'
as Line
From V$Session
Where Sid In
----------------------------
(Select Blocking_Session
From V$Session
)
----------------------------
;

spool off

Prompt
Prompt Note: Cut and paste, or type '@KL' to run.
Prompt

Set Feedback On Echo On Heading On

Friday, October 17, 2008

Data Modeler

To reverse engineer a schema:
  1. download the beta-version here.
  2. Select File
  3. Select Import
  4. Select DB Catalog
  5. Click 'Add' on the 'Connect to Database' window, and type in the requested info.
  6. Select the schema.
  7. Select the items you want.

To generate the DDL:
  1. Select View
  2. Select DDL File Editor
  3. Click Ok
  4. Click Generate

Thursday, October 16, 2008

Run EM and iSQL*Plus From Windows XP

Enterprise Manager:
Type into the browser's address bar:
http://localhost:1158/em/

iSQL*Plus:
Start the service and then type into the browser's address bar:
http://localhost:5560/isqlplus/

Tuesday, October 14, 2008

Java - A Way to Manually Sort an Array


public class mySort
{
public static void main(String[] str)
{
int[] array1 = {53,43,33};
int idx2, idx1, temp;
//----------------------------------------------
// The 1st index is set to 0. On each loop it's
// compared against the length, and incremented.
//----------------------------------------------
for (idx1 = 0; idx1 < array1.length; idx1++)
{
//--------------------------------------------
// The 2nd index is set to 1 position higher
// than the 1st. On each loop it's compared
// against the length, and incremented.
//--------------------------------------------
for (idx2 = idx1 +1; idx2 < array1.length; idx2++)
{
//------------------------------------------
// If the 1st number is greater than the 2nd
// number, the two numbers switch. The 2nd
// has to be stored so it's not overwritten.
//------------------------------------------
if (array1[idx1] > array1[idx2])
{
temp = array1[idx2];
array1[idx2] = array1[idx1];
array1[idx1] = temp;
}
}
}
//----------------------------------------
// display data when the sort is done
//----------------------------------------
for (idx1 = 0; idx1 < array1.length; idx1++)
{
System.out.printf("Final: array1(%d)= %d\n", idx1, array1[idx1]);
}
}
}

Java - If / Else vs. Switch

Both of these produce the exact same results:
if (opt == 1)
{
funcInst.func1();
}
else if (opt == 2)
{
funcInst.func2();
}
else
{
System.out.print("Invalid Option");
}
switch(opt)
{
case 1 : funcInst.func1() ;
break;
case 2 : funcInst.func2() ;
break;
default : System.out.print("Invalid Option");
break;
}


Java - Change Code to Object-Oriented

1. Move the main method to a script that will call the functions.
2. Create a method for each step.
3. Declare an object of the class.
4. Call functions thru the object name.

Monday, October 13, 2008

To Conditionally Call Code in SQL*Plus


Since SQL*Plus has no 'If' options (outside of queries) you need a different way to conditionally call another query. One way to do that is to have a query that checks for the condition you're looking for. If it is found, &Ex_If will be set to the name of the query I wish to run. It is first undefined so we're ready for the next execution.

I use this when there are some statements I need to jump around based on conditions. In SQL*Plus, you'll need to move those statements to another query, and then insert this type of code.

My main code is Ex_If.Sql:
Undefine Ex_If                        
Column Ex_If New_Value Ex_If

Select 'RunThis' As Ex_If
From Emp
Where Empno = &Empno;

@&Ex_If

If the condition is found, it calls RunThis.Sql
Select 'This Works!' From Dual;

Sunday, October 12, 2008

Finding Names in Code

This query will find column, table and variable names. The column and table name are based on the data dictionary; variable names are anything starting with '&'.

For example, the following code will generate the report as shown:Because of the length, the code is located on my web site as an attachment named NamesInCode.Sql.
  • It gets the name of a query from the user.

  • Creates an external table to read that file.

  • Creates a second external table of the words in that file if not a comment.

  • Creates a global temporary table of the intersection of table names from All_Tab_columns and the words.

  • Spools that list of table names.

  • Based on the table names, compiles a list of column names from All_Tab_Columns and compares that to the words.

  • Spool words found as column_names.

  • Spool words found that start with an ampersand.



Note: There is a new version of this query that includes other called queries.

Saturday, October 11, 2008

Searching a Long Field

As you've probably found out, the Long field type (soon to be expired) is hard to work with. You can't concatenate, use 'Like' or a host of other things. See the error posted below when I try to find which views are based on the EMP table:
SQL> Set Linesize 2000 Pagesize 60
SQL> Column Text Format A100 Word_Wrapped
SQL>
SQL> Select View_Name,
2 Text
3 From User_Views
4 Where Upper(Text) Like '%EMP%';
Where Upper(Text) Like '%EMP%'
*
ERROR at line 4:
ORA-00932: inconsistent datatypes: expected NUMBER got LONG
To allow you to get to this data, create a table with all the fields you need, but change the Long type to an LOB field type.
Create Table User_Views_Lob (
View_Name Varchar2(30),
Text Clob
);
Insert the records from the original table to the newly created table.
Insert Into User_Views_Lob
Select View_Name,
To_Lob(Text)
From User_Views;
You can now go after the data however you wish. If you want to print the entire text though, you'll have to set LONG to the length of the largest clob.
Set Long 15000
Select View_Name,

Text
From User_Views_Lob
Where Upper(Text) Like '%EMP%';

VIEW_NAME TEXT
------------------------------ -------------------------------
TOTAL_SAL Select Sum(Sal) Sum_Sal, Deptno
From Emp
Group By Deptno

DEPTRANK Select DeptNo, Count(*) Counter
From Emp
Group By DeptNo
Of course, you'll want to clean up at the end.
Drop Table User_Views_Lob;


Additionally, you can get to this data by storing it in a Global Temporary Table as shown:
Create Global Temporary Table GT_Cks
On Commit Preserve Rows
As
--------------------------------------------------
Select Table_Name,
To_Lob(Search_Condition)
As
Chk
From User_Constraints
Where Constraint_Type = 'C';

Select *
From GT_Cks
Where Chk like '%IS NOT NULL%';

Truncate Table GT_Cks;
Drop Table GT_Cks;

Friday, October 10, 2008

Display Column Names Not Found In Procedures

This was written as a solution to a question posed on ITToolBox. Because of it's length, it is stored as an attachment: Cols_Procs.Sql

  • It accepts a table name from the user.

  • It finds all the source names where the table name supplied is found in the text.

  • Based on that list, it creates a list of all the words in the text.

  • These words are spooled, and then an external table is created.

  • This external table is then compared against User_Tab_Columns for column names in that particular table.

Thursday, October 9, 2008

Java - Arrays

Calling program:
public class runmyArray3
{
public static void main(String[] str)
{
myArray3 m1 = new myArray3();
m1.getData();
m1.findLargest();
}
}

Called program:
public class myArray3
{
int[] n = new int[3];
int largest;

public void getData()
{
Scanner input = new Scanner(System.in);
for (int k = 0; k < n.length; k++)
{
System.out.printf("Enter value for n : ");
n[k] = input.nextInt();
}
}

public void findLargest()
{
largest = n[0];
for (int k = 0; k < n.length ; k++)
{
if (largest < n[k])
{
largest = n[k];
}
}
System.out.printf("\nLargest is %d\n", largest);
}
}

Java - JOptionPane

import javax.swing.JOptionPane;

public class jop
{
public static void main( String args[] )
{
String output = "Hi There \n\n";

JOptionPane.showMessageDialog( null, output,
"JOptionPane Test",
JOptionPane.INFORMATION_MESSAGE );

System.exit( 0 );
}
}

Java - Check String 2


public class cks
{
public static void main(String args[])
{
String s1, s2, s3, s4, output;

s1 = new String("x");
s2 = new String("y");
s3 = new String("abc xyz");
s4 = new String("Abc Xyz");

output = "s1 = " + s1 + "\n" +
"s2 = " + s2 + "\n" +
"s3 = " + s3 + "\n" +
"s4 = " + s4 + "\n\n";
//--------------------------------------------
// test with 'equals'
//--------------------------------------------
if (s1.equals("x"))
output += "s1.equals \"x\"\n";
else output += "not s1.equals \"x\"\n";
//--------------------------------------------
// test with '=='
//--------------------------------------------
if (s1 == "x")
output += "s1 == \"x\"\n";
else output += "not s1 == \"x\"\n";
//--------------------------------------------
// test for equality (ignore case)
//--------------------------------------------
if (s3.equalsIgnoreCase(s4))
output += "s3.equalsIgnoreCase(s4)\n";
else output += "not s3.equalsIgnoreCase(s4)\n";
//--------------------------------------------
// test compareTo
//--------------------------------------------
output += "\ns1.compareTo(s2) is " + s1.compareTo(s2) +
"\ns2.compareTo(s1) is " + s2.compareTo(s1) +
"\ns1.compareTo(s1) is " + s1.compareTo(s1) +
"\ns3.compareTo(s4) is " + s3.compareTo(s4) +
"\ns4.compareTo(s3) is " + s4.compareTo(s3) +"\n\n";
//--------------------------------------------
// test regionMatches (case sensitive)
//--------------------------------------------
if (s3.regionMatches(0, s4, 0, 3))
output += "1st 3 letters of s3 & s4 match\n";
else output += "1st 3 letters of s3 & s4 do not match\n";
//--------------------------------------------
// test regionMatches (true = ignore case)
//--------------------------------------------
if (s3.regionMatches(true, 0, s4, 0, 3))
output += "1st 3 letters of s3 & s4 match";
else output += "1st 3 letters of s3 & s4 do not match";

System.out.println(output);
}
}

Java - Check String

//
// CheckString.java
//
public class CheckString
{
public static void main(String arguments[])
{
// create an object

//String str = "Roses are red" ;
String str = new String("Roses are red");

System.out.println(" 1 ");
System.out.println("0123456789012");
System.out.println("Roses are red");
System.out.println(" ");

System.out.println("String is : " + str);
System.out.println("Length is : " + str.length());
System.out.println("Position 3 is : " + str.charAt(3));
System.out.println("Pos 6-9 is : " + str.substring(6, 9));
System.out.println("Char 'a' is at : " + str.indexOf('a'));
System.out.println("\"red\" word at : " + str.indexOf("red"));
System.out.println("Upper case : " + str.toUpperCase());
System.out.println("Lower case : " + str.toLowerCase());
}
}

Java - Loops

FOR LOOP
    for (int k=0; k < 3; k++)
{
s1.readData();
}


WHILE LOOP
    int k = 0;
while (k < 3)
{
s1.readData();
k++;
}


INFINITE LOOP
   for (;;)
{
s1.readData();

System.out.printf("Continue? Y/N ");
answer = userInput.nextLine();
if (answer.equalsIgnoreCase("y")) continue; else break;
}

Java - Calling Functions

This is the program that is executed:
public class callingClass
{
public static void main(String[] args)
{
calledClass calledClassInstance = new calledClass();

calledClassInstance.function1();
calledClassInstance.staticFunction2(); //call static function with
calledClass.staticFunction2(); //instance name or class name
}
}

This is called:
public class calledClass
{
long n1 = 10, n2 = 20, total, product;

public void function1()
{
total = n1+n2;
System.out.printf("\nTOTAL = %d\n",total);
}
public static void staticFunction2()
{
product = n1*n2;
System.out.printf("\nPRODUCT = %d\n",product);
}
}

Tuesday, October 7, 2008

How to Start and Stop Oracle Services on the PC


Select 'Start' in Windows
Choose
  • Control Panel
  • Administrative Tools
  • Services
Find the name of the Oracle services and create two batch files.

StartAll.Bat
net start OracleDBConsoleorcl10
net start OracleOraDb10g_home1TNSListener
net start OracleServiceORCL10

StopAll.Bat
net stop OracleDBConsoleorcl10
net stop OracleOraDb10g_home1TNSListener
net stop OracleServiceORCL10

OracleServiceSID = (the Oracle Database instance)
OracleORACLE_HOMETNSListener = (the listener)
OracleDBConsoleSID = (Enterprise Manager)

SID : the system identifier for the instance : orcl10
ORACLE_HOME: the Oracle home. : OraDb10g_home1

Hints

SQL hints (the things between /*+ */ )

1) There is no error posted if you type them wrong -- they just don't work.

2) If you use an alias in your FROM statement, you must use that and not the actual table name in the hint.

Monday, October 6, 2008

How to Put HTML in a Blog

To post html code to the blog
1) make sure there is no valid use of '~'. If there is, switch to another character.
2) search and replace the following in the order shown.

FIND REPLACE
< ~lt;
> ~gt;
&nbsp; ~amp;nbsp;
& ~amp;
~ &

Sunday, October 5, 2008

ORA-01722: invalid number

Normally, I have no problem renaming a column its original column name after some function. This time, it's posting 'invalid number', but only after I inserted the 'Order by'.

1 Select To_Char(Trunc(Datetime) + (Trunc((Datetime - Trunc(Datetime)) *48) / 48), 'dd/Mm/Yy Hh:Mi') As Datetime
2 , Count(*)
3 From Ext_Ittbl1
4 Group By To_Char(Trunc(Datetime) + (Trunc((Datetime - Trunc(Datetime)) *48) / 48), 'dd/Mm/Yy Hh:Mi')
5* Order By To_Char(Trunc(Datetime) + (Trunc((Datetime - Trunc(Datetime)) *48) / 48), 'dd/Mm/Yy Hh:Mi')
SQL> /
Group By To_Char(Trunc(Datetime) + (Trunc((Datetime - Trunc(Datetime)) *48) / 48), 'dd/Mm/Yy Hh:Mi')
*
ERROR at line 4:
ORA-01722: invalid number

Time Intervals


This request came from the ITToolBox. Based on the following data
ID DATETIME
-- -----------
1 10/03 09:00
2 10/03 09:01
3 10/03 09:20
4 10/03 09:31
5 10/03 10:00
6 10/03 10:10
7 10/03 10:40

They wanted a total count in half-hour intervals. Tom Falconer put together the logic for this. I made a few refinements, and fixed a minor error, but had to keep this for future reference. The ID field shown in the table, is not necessary or used in this code.
Define Date_Time = "To_Char(Trunc(Datetime)+(Trunc((Datetime-Trunc(Datetime))*48)/48),'dd/Mm/Yy hh:Mi')"

Select &Date_Time As Date_Time, Count(*)
From Ext_Ittbl1
Group By &Date_Time
Order By &Date_Time;

Saturday, October 4, 2008

Display All the Digits in a String (pre 10)

Conn hr/hr

Select Translate(Phone_Number,
' !"#$%&''()*+,-./:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~' ,' ') As
Digits,
Phone_Number
From Employees;
With version 10, you can use Regexp_Replace as shown:
Select Regexp_Replace('abcABC123^&*','[^[:alnum:]]') 
From Dual
SQL> /

REGEXP_RE
---------
abcABC123