SQL to find the last Saturday of the year

Satya commented on my post about finding the first or second Monday in a month asking how to find the last Saturday of a year using SQL. This is a good question as I think it is typical of the battles people fight with dates in Oracle.

So here we go… For this example we’ll use sysdate but you can use a date column or a to_date instead.

SQL> select sysdate from dual;

SYSDATE
---------
13-SEP-06

Now we’ll jump forward a year and start working backwards:

SQL> select sysdate+numtoyminterval(1, 'YEAR') from dual;

SYSDATE+N
---------
13-SEP-07

Now that we’re safely into next year we’ll reel it back to January 1st of next year using the trunc function to truncate the date down to the year.

SQL> select trunc(sysdate+numtoyminterval(1, 'YEAR'), 'YEAR') from dual;

TRUNC(SYS
---------
01-JAN-07

To work with the last week of the year we’ll go back 8 days. We need to go back 8 instead of 7 because we’re going to use the next_day function later which only looks after the date it is passed.

SQL> select trunc(sysdate+numtoyminterval(1, 'YEAR'), 'YEAR') - 8 from dual;

TRUNC(SYS
---------
24-DEC-06

Now we use the next_day function to look for the next Saturday after the date we’ve got.

SQL> select next_day(trunc(sysdate+numtoyminterval(1, 'YEAR'), 'YEAR') - 8, 'SATURDAY') from dual;

NEXT_DAY(
---------
30-DEC-06

So we figured out the last Saturday of this year by taking today’s date, adding one year, going back to January 1 of that year, stepping back 8 days from then and looking for the next Saturday.

Hope this helps Satya! Thanks for the great question.

oracle, dates, database, sql, dba, dbms, database development, database programming

Finding the first or second Monday in a month

Syam asked a while ago how we could find something like the first Monday or third Saturday in a month. Well Syam, it’s taken me a while to respond but here we go.

For this example we’ll use sysdate as input but any Oracle date will work. You can also substitute any other day of the week for Monday.

The first day of the month is probably a good place to start:

SQL> select sysdate from dual;

SYSDATE
---------
18-JUL-06

SQL> select trunc(sysdate, 'MONTH') FROM DUAL;

TRUNC(SYS
---------
01-JUL-06

Now that we’ve got that we can find the first Monday with the next_day function. Of course we need to remember the next_day function looks for the next named day after the date provided so we subtract 1 day from the date in case the first is a Monday.

SQL> select next_day(trunc(sysdate, 'MONTH')-1, 'Monday') from dual;

NEXT_DAY(
---------
03-JUL-06

Now that we have the first Monday of the month we can add 7 days to find the second Monday or 14 to find the third.

SQL> select next_day(trunc(sysdate, 'MONTH')-1, 'Monday')+7 FROM dual;

NEXT_DAY(
---------
10-JUL-06

SQL> select next_day(trunc(sysdate, 'MONTH')-1, 'Monday')+14 FROM dual;

NEXT_DAY(
---------
17-JUL-06

So from here you can change the day you’re looking for or the week number you want it in.

oracle, date functions, sql, database, database development, pl/sql

Oracle Auto Increment Columns – Part 2

Three separate people have commented on my previous article on How to Create Auto Increment Columns in Oracle asking how they can retrieve the value of an auto increment column for use later in their code. Well Daniel, Shaun and Zach, here’s the answer.

After you have referenced sequence.NEXTVAL for a particular sequence (or it is referenced on your behalf by, say, a trigger), you can then reference sequence.CURRVAL to get the value just used for NEXTVAL.

To illustrate this we’ll use the table, sequence, and trigger created in my previous article.

If we insert a row into the table test, the trigger test_trigger automatically calls test_sequence.NEXTVAL.

SQL> insert into test (name) values ('Matt');

1 row created.

We now have test_sequence.CURRVAL available in that session.

SQL> select test_sequence.currval from dual;

CURRVAL
----------
8

In this simple example we can confirm this is the same value just used with this simple query:

SQL> select * from test
where name='Matt';

ID NAME
---------- ------------------------------
8 Matt

Now if we wanted to use this value in another SQL statement, say for an insert on a table which uses this as a foreign key constraint, we can include it on our insert like this:

SQL> insert into tool (owner_id, tool)
values (test_sequence.CURRVAL, 'hammer');

1 row created.

SQL> select * from tool;

OWNER_ID TOOL
---------- ------------------------------
8 hammer

Of course, if we just want to see the value of test_sequence.CURRVAL we can select it from our favorite table dual.

SQL> select test_sequence.currval from dual;

CURRVAL
----------
8

For the table, sequence and trigger used here see my original article on auto increment fields.

Oracle SQL Developer – A New GUI For Database Development

raptor_image.jpgAt long last Oracle has come up with a modern product to replace SQL*Plus.

Oracle SQL Developer (formerly Project Raptor) was released last month with little fanfare; however its release represents a quantum leap in functionality and ease of use over previous Oracle provided SQL development tools.

SQL Developer is Oracle’s new, free graphical tool that enhances productivity and simplifies database development tasks. With SQL Developer,you can:

  • Browse database objects
  • Run SQL statements and SQL scripts
  • Edit and debug PL/SQL statements
  • Run provided reports
  • Create and save custom reports

Now all these features exist in Quest Software’s product Toad for Oracle so why switch? Well, here’s the hook… SQL Developer is free. Yup, free. It also has another strategic advantage over Toad… SQL Developer is cross platform! I am currently running it side-by-side on Mac OS X and Windows XP, and there is also a Linux version available. The Mac and Windows versions are both extraordinarily easy to install, configure, and use. I can only assume the Linux version follows this trend.

So what’s the down side? Well, I’m personally disappointed that they changed the name from “Raptor” to “SQL Developer”, but that aside, you can’t use it on databases earlier than 9.2.0.1.

A small problem for Toad users will be adjusting to the date format in SQL Developer. Toad defaults to showing the time when displaying date data types while SQL Developer will only show the date. The solution to that is to add a TO_CHAR around the date column in the query (for more information on the TO_CHAR function, check out the Displaying Dates section of my article Oracle, SQL, Dates and Timestamps). Toad users may also miss being able to click on the header of a column to change the sort order of the output, but this can also be overcome by adding an ORDER BY clause to the query.

Setup was quick, taking less than a minute to download, unzip and connect (yes, one minute, you’ve probably spent more time reading this than it takes to install). As you’re setting up SQL Developer you’ll notice that it does not require a TNS Names or other descriptor file to find databases. When you set up a connection you are prompted for the hostname and SID of the database. This assures maximum flexibility but does run the risk of confusing end users, since they can nickname the connections anything they want to.

Below are some screenshots of SQL Developer, but if you’re interested, just go out and get it. It’s free after all, what do you have to loose.

SQL WindowPackage Editing


Table BrowsingReports

Click on the thumbnail for a larger image.

oracle, sql, sql developer, database development, database administration, dba

Oracle Timestamp With Time Zone

Last week Warren left a comment on my story Converting Time Zones in Oracle asking how he could output dates with time zone like: “17-Mar-2006 14:30:00 EST”.

Well, after a bit of digging it turns out the answer is not as simple as it sounds. The traditional Oracle DATE and TIMESTAMP datatypes don’t store time zone information. A workaround might be to store time zone information in a separate column in the table, but that seems like it could cause some confusion.

Well, it looks like in version 9i Oracle has added a new datatype to handle exactly this. The TIMESTAMP WITH TIME ZONE datatype allows a time zone to be stored with a date and time either in offset from UTC or by abbreviation.

The TIMESTAMP WITH TIME ZONE datatype can be declared in the table definition anywhere you would have used DATE or TIMESTAMP. To store a date/time/time zone into a row Oracle has also added the function TO_TIMESTAMP_TZ which acts much like the familiar TO_DATE function, however will recognize TZH, TZM, TZR, and TZD for time zone hour, minute, region, and abbreviation respectively.

To retrieve time zone information you can apply the same new abbreviations to the familiar to_char function when selecting a column of type TIMESTAMP WITH TIME ZONE.

Rather than go into any more detail here, check out this article from Oracle Magazine. It covers the topic very well including example code.

sql, oracle, database administration, database, dba, database development, dbms, pl/sql