Archive for the 'Code Monkeying' CategoryPage 2 of 4

PostgreSQL INSERT RETURNING Rocks My Socks

A common need for web apps is to insert something into a database table and then immediately find out which ID got assigned to your new thing so that you can refer to it later in the script (probably while inserting more data).

A lot of folks start out doing something along the lines of:

INSERT INTO Addresses (address, city, state, postalcode) VALUES ('123 Main St.','Springfield','MA','01109');
SELECT max(id) as ID FROM Addresses;

After that, the folks on Microsoft SQL Server tend to discover the combination of SET NOCOUNT ON and @@IDENTITY:

SET NOCOUNT ON;
INSERT INTO Addresses (address, city, state, postalcode) VALUES (’123 Main St.’,'Springfield’,'MA’,'01109′);
SELECT id = @@IDENTITY;
SET NOCOUNT OFF;

Now, at my new gig, we use PostgreSQL. Today, I finally found myself wondering if/how I could achieve the NOCOUNT/@@IDENTITY behavior. Turns out, it’s super easy and almost even sexy (since version 8.2, I guess):

INSERT INTO Addresses (address, city, state, postalcode) VALUES ('123 Main St.','Springfield','MA','01109') RETURNING id;

That, my friends, is HOTT.

Sure, it’s non-standard SQL, but what’s the point of picking a particular RDMS if you don’t use the magic that it offers?

Birds Flying High, You Know How I Feel

Near the end of August in 2001, after a four month period of being unemployed, I finally found a job with a Boulder company called e-InfoData.com (Holy internet cliche overload!). We’ll round the ensuing passage of time up to five and a half years for the purpose of this discussion.

In that period the company changed it’s name to InsightAmerica, moved its office to Broomfield, and eventually was acquired by a corporate giant (name uselessly withheld). The basic “job” of the company never really changed, and the work was mostly interesting on a nuts-and-bolts level (I still think we regularly pushed ColdFusion well beyond its normal bounds and managed to make it work.), even if the bigger picture at times gave me the heebee-jeebees.

At a more micro level, I’ve had the opportunity to work with some amazing people (particularly within the technology teams - but outside that, as well). In fact, most of the people I currently consider my best friends were first coworkers.

On a work level, there have certainly been ups and downs, but on a personal level this job has been nothing but positive.

You’ve probably already guessed that I’ve decided it’s time for me to move on.

  • I’m going back to Boulder. (meh. I’ll miss my 10 minute commute, but I only think I’m doubling it.)
  • It’s a very small company. (sweet! I enjoy the dynamic of a small company much more than a megalocorp.)
  • I’ll be working with an old friend. (yay! This is actually the only reason I applied for the job when I saw it come across the wire.)
  • I’m going to be working daily on a Mac. (w00t! This excites me unreasonably. Not to mention the HUGE monitors they use.)
  • I’ll eventually get to work with Ruby on Rails professionally. (double w00t!! I’ve been a fanboy since the early days, though I’ve never actually done anything with it.)

I’m also leaving a lot of friends behind. Hopefully I’ll be able to keep in touch - the Denver Metro area isn’t a very big place, really. Some of us already have outside-of-work connections, but I want to cultivate more of those.

So, yeah… That’s what’s going on with me.

Let’s have Nina Simone carry us out, shall we?

Its a new dawn
Its a new day
Its a new life
For me
And I’m feeling good

Testing Dorkosity

I work with some mega high scale geeks. One of them wrote a bot to monitor our personal blogs and announce updates to our internal IRC channel.

This is a test of that bot.

KnuckleRockers.com Plan of Action

I’ve actually be having a lot of fun thinking about this and getting ready to move into planning and design.

First and foremost, I’m going to use this as a learning exercise to teach myself some new technology, so don’t expect a very rapid turn around. I figure I’ll either build the site using Ruby on Rails or Django, so that’ll be cool. I think I have the option of using PostreSQL on the backend, so I might do that, as well. (Not that I expect this to be a big test of a database…)

As for features, I think we want the following for submissions: tagging, commenting, searching, ranking, and maybe a “favorites” pool (favorites could work as a binary ranking system… the more a submission is “favorited”, the more popular it is…). Ideally there would be an RSS/Atom feed for the latest submissions.

Users need profiles with optional links to blogs, Flickr accounts, MySpace pages, etc.. They could also have some semi-social functionality like “buddies”, and so forth.

Hopefully we can run out some t-shirts/stickers/whatev from the best submissions. There’s some vague potential for some actual goods, but that’s nowhere near reality at this point.

What else do we want/need?

Paging Oracle Results

At my workplace, we often like to page through query results. That is, we’d like to show results in bunches of, say, 50.

Some databases (none that we use: PostgreSQL and MySQL) do this using LIMIT and OFFSET:
select * from table
where blah = 2
order by thing1, thing2
limit 50 offset 100

That query would give you the 3rd “page” of 50 results. (Note: I believe MySQL has shorthand: LIMIT 50,100)

I think Omnidex (a funky flat file indexing engine we use) lets us do something like:
select top 50 skip 100 * from table
where blah = 2
order by thing1, thing2

SQL server has the TOP, but I have no idea how to do offset/skip…

Anyway, what I do know is my boss kept bugging me to figure out how to do it in Oracle now that we are playing with a new database on that platform.

So, thanks to the internets, I present you with the wonderfully wacky world of paging in Oracle:

Select * from (
select t1.*, ROWNUM rn from (
select * from table where blah = 2 order by thing1, thing2
) t1
) where rn between 101 and 150

Key bits:

  • You have to alias the inner-most select if you want to select * (That’s the “t1″ jazz.)
  • ROWNUM is a calculated field. Each select has it’s own rownum column under the covers. This the real reason there are so many nested “views” to do this. The first select has rownum values that are calculated BEFORE the “order by”. The second select has rownum values that are calculated AFTER the “order by” in the inner-most select — this is the rownum set we actually want to filter, so we include it in the select (with an alias). The outer-most select is needed to actually apply that filter.

Caveat: My friendly neighborhood Oracle DBA tells me, “Rownum is virtual, you aren’t guaranteed that 101 through 150 are the same every time.”

Alternative: Said friendly neighborhood Oracle DBA came back with another method that I have yet to play with seems to work nicely:

Lets go this route, subtle difference, but there is a reason.

Select * from (
Select a.*, rownum rnum From (
select * from table where blah = 2 order by thing1, thing2
) a where rownum <= 150
) where rnum >= 101

It has to do with the way Oracle processes the COUNT(STOPKEY). Also I had to remember that in 8.1 that stuff wouldn’t work. With 9i and above we should be good to go.

MacGyver to the Rescue

So get this: That problem I had with ColdFusion 5 and Oracle9? Well, at this point the work around may be what we call a “gateway” solution.

That means we have CF5 post search parameters via HTTP (using the CFHTTP tag) to a ColdFusion MX 7 server, which actually does the search on the Oracle database (MX and Oracle like each other fine). The CFMX code then takes the resultsets from the Oracle reference cursor and outputs them as WDDX XML. So, that WDDX gets deserialized on the CF5 box and voila! the CF5 box has its data to play with.

Unreal. Don’t worry, this sort of gymnastics is just as ridiculous as you think it is (almost as ridiculous as the fact we’re still using CF5). The thing is, it’s likely to end up in production…