- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
The real WTF is that a table called dual has one row in it.
Admin
OK, I get that "select *" means "poor performance," but is that really a WTF-worthy article? We must really be scraping the bottom of the bad code samples barrel.
Admin
I don't know the particulars for oracle sequences. In Sql Server you just INSERT INTO CUSTOMERS (NAME, ETC ) VALUES (NewName, OtherInfo ); return scope_identity()
Or set an output var to the scope_identity(), whichever. If you don't have any history tables or triggers, a simple return @@IDENTITY will work. It's not rocket science.
30 seconds of googling found the equivalent for Oracle.
"The general syntax for the RETURNING clause is:
INSERT INTO
(c1, c2, .., cn) VALUES (v1, v2, .., vn) RETURNING <expression> INTO <variables> ... INSERT INTO Contacts (fname, sname) VALUES (pFirstname, pSurname) RETURNING ContactID INTO pContactID;"Admin
Admin
Still a WTF, not denying that, but I doubt the query was used quite as the story suggested.
Admin
I can (almost) believe this sort of code exists somewhere in the universe, but the usage as presented in the article simply doesn't make sense. at all. even as a WTF.
Admin
(disclaimer: I am not very knowledgeable about databases.)
If they want to ensure they have a unique ID for each customer, but, as one commenter mentioned, it would be nice to do it in a way that allowed multiple concurrent users to not have collisions, why not simply use, say, the number of milliseconds since the epoch at the time the insert query is launched? The IDs won't be sequential, sure, but this guarantees they'll be unique, later customers will always have higher IDs, and you won't have stupid select queries like this one, which looks wrong even to talentless newbies.
I normally wouldn't care about captchas, but seeing 'Gravis' made me smile a bit (for all the old games that expected GUS and would go silent if you had a Soundblaster 16 :) )
Admin
Admin
Sequences are linear, so the number we returned should always be max(customer_id). Doing anything remotely like this is just stupid (assuming it is to find the most recent customer added)
Admin
Jim creates new Customer ACME industries (and takes his time filling in the details). The Customer is assigned ID 65789 Meanhile, Boris creates a new Customer Kresnovik Transport Concerns and quickly enters the detail. The customer is given 65790. When Boris uses this query to find his customer ID, he gets 65789 back. Depending on how and when the SQL gets updated (and to a degree how much Jim drags his feet), Jim could get 65789 (correctly) or 65790....
So neither method really works for concurrent users. I would have thought, given you just entered the customer detail, it would be reasonably trivial to query that detail...but maybe that's just me
Admin
How do you get it with an auto-number field/column?
Addendum (2012-02-20 16:08): I mean, I'm no SQL-genius, but round-tripping to the database for a number that you probably don't need is silly. Now if you DO need that number ... :shrug:
Admin
Admin
Admin
Though I may reach around just 'cause you're a good sport.
Admin
My guess is that they went to all this trouble so they wouldn't have to have an "activeCustomer" flag on the table. You know, one that would indicate the record was in use.
Which is still a horrid design.
But storing the active flag in the WHERE clause of an SQL query has to be a new high water mark in anti-patterns.
Admin
On the subject that this query might be used to get the last inserted id of an insert: There are WAY better ways to achieve this in a transaction than doing anything remote to that.
For example, off the top of my head I know that last_insert_id returns the id that the last insert statement generated in mysql. A google search resulted in @@IDENTITY for Sql Server. And I am quite optimistic that in all major databases some feature like this exists.
So there is no excuse to this query.
Admin
This is the sort of thing, why I leave database stuff to someone else. Because it seems like a nice bright line of where to stop.
Admin
The use as suggested in the article indeed makes no sense, even as WTF. My guess is that this query is executed, but the result is ignored completely. The developer working there now (or the boss' nephew, w/e) is too afraid to throw it away and zealously keeps it up to date manually when customers are added or removed.
Admin
You are trolling right? Like... did you miss the 4500 lines of while != code...? The select * is just the icing on this one.
Admin
TRWTF is that they didn't index the field and set the optimisation level to make this clever code run fast.
AmIright?
Admin
Admin
I wasn't saying either method works, they're both made of fail. People should learn how to use the tools a database gives them - every major db has a way of outputting identifiers after they're generated, and for anyone working with these platforms, it should be basic knowledge.
Admin
Admin
Oracle has a returning clause that will hand you back a result set with the value in it.
Admin
The WTF was that they served ham sandwiches even though they knew he was Jewish......
Admin
We have no context around the != code. It could be generated. The execution plan would look the same whether you include a myriad of inequality operators or a NOT IN statement. So what difference does it make how it looks? Neither has much asthetic appeal, anyway, so you pick a solution and go with it. That's no WTF, just reality.
Admin
Kind of surprised how many people here are not comfortable with:
Database generated id sequences Using transactions to select and update a handmade sequence table in one atomic step Returning data from a stored proc or insert statement Simply making CustomerId a GUID instead of a monotonically increasing sequence number
All these approaches have their benefits and drawbacks (as opposed to the approach found in the wild... which is full of fail). Depending on your situation you would choose different ones at different times...
Assigning an id to a business object reliably? This is bread and butter stuff!
Admin
The right way is just to generate a random customer ID. If there's a collision, well, you've been customer #524356 for long enough, it's time to let someone else have a go.
Admin
INSERT INTO CUSTOMERS ( ID, NAME, ETC ) VALUES ( CUSTOMER_ID_SEQ.NEXT_VAL, NewName, OtherInfo ) RETURNING id INTO some_variable;
Admin
I can imagine a design that does things this way. It goes without saying that it's a horrible and broken design, of course. But I wouldn't rule the possibility out entirely.
Admin
Well, if you define an opinion on the original code, and the suggested "solutions" as "unrelated", then I guess so.
Admin
Nope, you would write something like
<SEQUENCE>.CURRVAL holds the last generated sequence number in your transaction (you will not get numbers generated by other users)
Admin
Admin
You all seem to be missing the point of this query.
It actually makes perfect sense, iff the submitter has meaningful IDs and letting the database generate them would break something else. (Well, OK, maybe not perfect sense...)
My guess (FWIW) is somebody assigns the IDs by hand (perhaps for regulatory reasons), the tea boy updates the query accordingly, and nobody has any idea why - its just how it has always been done.
So TRRWTF has to be "using meaningful IDs as a primary key".
We now return you to your regular trolling.
Admin
The Real WTF is the guy that thought doing the "select max(id) from table" is safe when used in transactions but using transactions gets too "database-specific". LMAO
Admin
That's how Skynets get started
Admin
Are you from one of the DB Engine trade unions?
Admin
if you really want to screw things up add an extra row to the dual table. hilarity always ensues.
Admin
Because when that condition returns almost all rows, DB engine will not use such index, it would be pointless. Index will be used only when it shrinks result set significantly, otherwise just ignored and do the sequential scan.
Admin
Within the same transaction and immediately after the insert using NEXTVAL... SELECT CUSTOMER_ID_SEQ.CURRVAL FROM CUSTOMERS;
...should do it from what I cam tell from the docs here: Using Sequences
(Askimet bites whale dung)
Admin
This looks like someone who previously programmed SAT solvers migrated to SQL.
Admin
And what did they do with the ATM after the "accident"?
Admin
Admin
Admin
It was designed as a two row table you were never supposed to directly query, which now only has one row in it, which doesn't receive any physical or logical IO, but you have to use it to obtain table-free results.
Can't make this stuff up. http://en.wikipedia.org/wiki/DUAL_table
Admin
It never occurred to me that this is odd. It's just "the way to do this sort of thing" in Oracle's brand of SQL. Now you mention it, it does come across as somewhat idiosyncratic.
Admin
Admin
Its obvious; the database uses an auto-increment. So they insert a row, the database assigns an ID, they then do a select with all known customer IDs. Whatever it returns must be the new one.
Admin
It's obviously wrong. The proper way of doing it is to start from 1 every time and keep incrementing the id_customer until the primary key constraint stops throwing an Oracle error. It's the only way to be sure.
Admin
You win. There is no need to discuss this further... I about choked on spit laughing at that.