- 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
Sad, kind of like when King Kong died.
Could this query be an example of "machine generated" code? It looks like an awfully complex monster. Or maybe it grew and evolved?
Admin
Looks more like de-evolved.
Admin
I wonder - what all thos inserts were doing.. and if they'll be missed..
Reminds me of another time when I was asked to export data into Clipper from Oracle - run a loop to remove unwanted records, and re-import the results back to oracle... because oracle was too slow.
I ended up rewriting the deletes where clause so it took less than a second.. all was well.
Admin
Ahhhh, this sounds similar to a report I had to help run - except it involved a Mail Merge, some Access tables that macro'ed an Exchange public folder, and a half dozen other pieces of voodoo. Lovely thing it was.
Admin
Reminds me of an old product called Case Tools - if you're familiar with the code it spit out, I'm sorry.
Admin
Wow...complicated. Amazing that The Report managed even to run with that crud...
Admin
Oh, come on now.... those function calls are somewhat analogous to the lazy-coding style:
Admin
<FONT face=Tahoma>Seeing the function snippet literally made me say "OUCH!", to think that it's still just a small portion...
I feel for the server that took this kind of torture...
</FONT>
Admin
I've never heard of a machine generating a cursor. It just goes to show, that if you can't force SQL server to do a table scan, do one manually with a cursor.
I bet this report used to run off of flat files (or excel files) instead of database tables, so the report designer had to 'manually' relate the files. When they moved into SQL, the idiots simply translated it into T-SQL from the VBA or whatevor.
They should have just used Visual FoxPro.
Admin
At least they used a FORWARD_ONLY cursor. That surely sped things up...
Admin
Hey, if you're using a proper functional language, it'll cache the return values of func(x) and func(y) for later use, and you don't need to use such counterintuitive things as temporary variables.
Admin
It took me a while to get what was happening, but I think I get it now. It's like a 'view' as written by chimps.
This "fnc_GetCojobTb(X)" function clearly takes an integer and then appearantly returns some rows that link a job code to a job id. The last little bit of evil code in the post reads every job code and for each one, pulls the first 5 job ids associated with that code, and puts them into a temp table of some kind. Then it likely selects from that temp table to return the relevant rows.
The whole function was probably replaced with a single select with one join, or better yet a view. Or even better, the calling statements were rewritten properly and the function was eliminated entirely.
Admin
Admin
Ah, brillant
I challenge anyone to write a non-WTF-ish T-SQL query that uses cursors
Admin
thank you! i dont know what it is, but SQL tends to turn my brain to jelly... i was reading it... thinking ... looks ... complicated .... don't ... get ... it .... w..tf... is ...the ...
Admin
Reminds me of several instances where I (as a function-oriented programmer... someone else's label) created SP's that used multiple nested cursors to do something that was later rewritten using two queries... I've learned a lot since those days... unfortunetly that was last month....
Admin
<FONT face=Georgia>How many virgins had to be sacrificed daily to please The Report? </FONT>
Admin
I have NO idea what's going on in this code. Can someone please step us through it? Otto's summary was nice, but I want to know just why this is a wtf.
Admin
72.
Admin
The function to calculate that quantity was embedded in the posted function - unfortunately, by the time it finished the calculation, they weren't virgins anymore...
Admin
The server that had that code on it should be washed thouroughly with bleach, and sent to Yucca Mountain to be buried for the next 250,000 years, or until the next epoch, whichever comes last. The developer that wrote the code should be sent to maintain the server on site and in person.
<shudder>
Admin
It is using a function to call a cursor to return a table with 5 rows. And being called many times.
There are many other ways of doing this. All are faster. I can't think of a slower way. Anyone?
Admin
"think about side affects"
In a functional language, there are no side effects. You're thinking of imperative languages.
http://en.wikipedia.org/wiki/Functional_programming
Admin
I've seen queries in procs that select a data subset into a dynamically generated temp table, then select everything from the temp table, then trash the temp table, then repeat it in the center of a deeply nested series of subqueries - I swear, the lights would dim and you could hear the disk motors straining to keep up
Admin
Are you challenging us? :) Something involving a digital camera, a wooden table and a scanner comes to mind...
Admin
I'll be damned - I learned something from TDWTF - thanks :)
Admin
Thanks!
Admin
Yeah, I'll bet though that it was added after the fact at an attempt to 'optimize' the report
Admin
Admin
<FONT face=Tahoma>WAITFOR DELAY '05:00' ? :)
</FONT>
Admin
In SQL Server, this is a "table valued function" i.e. a function that returns an object that behaves like a table, can be SELECTed from, JOINed to etc.
It's not really that WTF. Yes, the cursor is WTF, but for 5 rows, kinda WTF-lite. When it's used in the FROM section of the SQL query as a substiture for a "real" table, it only gets evaluated once.
A real WTF (and I expect the part we weren't shown) is when a function containing a cursor is used in the SELECT part of the SQL query, where the function needs to be re-evaluated for every row in the resultset.
It really is a pity that so many SQL programmers don't know WTF derived tables are & how to use them.
Admin
So, where's the bit where the user now don't trust The Report cuz it runs too fast, and there's no way that it would generate real data that fast - and what's his name had to put in a sleep() call in there to fake it?
Admin
Just curious, do rdbms' have the query-equivalent of file-not-found?
Admin
Bah.
To me SQL is like HTML. Its not programming at all.
I really think is unteresting how your ORDER BY your socks.
--Tei
Admin
Please oh PLEASE post the replacement query!
Admin
Somewhere, deep in the guts of the UK National Air Traffic Services processing system (the guys responsible for routing and timetabling), there's a COBOL program which creates several dozen temporary tables in the course of its activities.
<br/>
While working on a summer placement at Uni, they wouldn't let me 'fix it'. I guess it was their 'The Report'.
<br/>
Being COBOL, and an UK government system, it's possible it was written before SQL was standardised, CRTs were invented, or Edison invented the lightbulb.
Admin
Soooo, the tables were really bowls of rocks, and the computer was a monkey playing towers-of-hanoi with the data ?
Admin
It's actually 5 more-or-less random job ids, since there is no sort. It's just possible that selecting 5 random job-ids was part of the spec. However I suspect that once upon a time there was only one job id per code. Then along came a code with 2 job ids, and someone wrote a predecessorof this mess to cope with 2. Then along came a case where there were 3 ... and the most recent person to visit the code thought that there would be no more than 5. Ugh.
Admin
<FONT color=#000000>The segment of sql from the function correlates job ids for a given job code where the job code is (i assume) not marked as deleted (not entirely sure what <FONT face="Courier New">del_ind</FONT> is but thats a reasonable assumption). There are no other constraints placed on this query so I can also assume that there are never more than 5 jobs per job code. The same resultset can be generated from:</FONT>
<FONT face="Courier New" color=#000080>SELECT <FONT color=#000000>job_cd, job_id </FONT><FONT color=#000080>FROM </FONT><FONT color=#000000>cojobs </FONT><FONT color=#000080>INNER JOIN </FONT><FONT color=#000000>jobs </FONT><FONT color=#000080>ON</FONT><FONT color=#000000> cojob.job_cd = jobs.job_cd </FONT><FONT color=#000080>WHERE</FONT><FONT color=#000000> del_ind = 0</FONT></FONT>
Without seeing the entire query, there is a better than good chance that all of the inner joins using the function can be replaced with a well constructed set of joins and where clauses.
The WTF here is using row by row processing (a cursor), that can be replaced with a (much simpler and more efficient) query, when relational databases are highly optimised for set based processing (SQL is a set based language), and that this row processing was done 11 times for EVERY row in the view.
Admin
(display "Yeah, sure, no side effects.")
Until you are doing anything with your code, like, say, input/output...
Admin
There are no stupid questions, only stupid people who ask questions...
Admin
I once had the fun job of rewriting a set of stored procedures, and was able to replace a cursor with a couple of selects using temp tables. Sped one sp up by a factor of 30.
Admin
I'm guessing that the many calls to that function, passing in different values as arguments, is done to try to "crosstab" the data (i.e., summarize many rows into many columns).
T-SQL is amazing ... In the system I am dealing with now, the guy who wrote the SQL did not know any of the following:
* Derived tables
* Left outer joins
* UNION
Ah, but what do they know?
* Temp Tables
* Cursors
* Dynamic SQL
They made good use of the "temp table cursor-fill then update technique", something well beyond my T-SQL skills. You see, I just write a SELECT that joins the tables as needed and returns the results. However, someone with advanced knowledge of SQL knows that the better way is to:
1) create a huge temp table
2) use a cursor to fill up columns that come from one table
3) write UPDATE statements that update the temp table with related data from other tables (i.e. to avoid those messy joins)
4) repeat 1-3 as necessary
5) combine everything using another cursor into another temp table
6) return the final temp table
I just replaced a 500-line stored procedure with a 26-line select. Only my 26 lines now have some comments.
Admin
Blasphemy! Dirty troll.
SQL is the art of thinking about sets unlike (filthy imperative) row based programming.
-- Stretch your mind to encompass the superset
Admin
They fall under the category of Declarative programming
But when you include stored procedures the distinction gets very blurry.
Admin
>>The same resultset can be generated from:
<FONT face="Courier New" color=#000080>>>SELECT <FONT color=#000000>job_cd, job_id </FONT><FONT color=#000080>FROM </FONT><FONT color=#000000>cojobs </FONT><FONT color=#000080>INNER JOIN </FONT><FONT color=#000000>jobs </FONT><FONT color=#000080>ON</FONT><FONT color=#000000> >>cojob.job_cd = jobs.job_cd </FONT><FONT color=#000080>WHERE</FONT><FONT color=#000000> del_ind = 0</FONT></FONT>
<FONT face=Arial>Aha, but it's not the same resultset, is it ? It's not guaranteed to have exactly 5 rows and it doesn't have an ascending sequence number column both of which the table-valued function provide. And who knows what dependencies exist on those requirements.</FONT>
Admin
Um, some of us just don't really work with databases and/or sql.... (in case you're not a regular around here, 'file-not-found' is kind of a running joke)
Admin
Well, there's another thing. If I read this correctly, it fetches up to five ids and then inserts exactly five ids. And if there are less than 5 ids per cd, it appears to reinsert some ids from a previous cd.
I'm glad I don't know SQL well enough to write something as bad as this.
Admin
Maybe it will. But the idiom
<FONT face="Courier New" size=2>if(func(x) > func(y))
then return func(x);
else return func(y);</FONT>
is kind of dorky because if return func(x) ever executes, then there's never a chance to return func(y), rendering the else redundant.
What's truly scary is that this particular construct shows up in the original K&R, and you'd think those guys would know better, even in 197x.
Of course, if you're using one of those massively silly languages that does logical blocking by indentation instead of bracing symbols or commands (as God intended), then you have to write something like this, and you have my condolences.
Admin
Actually, if I read the code right, the table-valued function has up to five rows; and you can get the same behavior with a TOP clause in most databases I've worked with (or a FETCH FIRST <n> ROWS ONLY clause in the last version of DB2 I used).
The sequence number is a little trickier, if you have an old SQL implementation. A current one (that includes the OLAP functions) should allow you to put ROW_NUMBER() OVER() or some variation thereof in your select list.