I'll go first.
I'm 100% in the set-operations camp. But what happens when the set logic on the entire desired input domain leads to a such a large retrieval that the query slows down significantly, comes to a crawl, or basically takes infinite time?
That's one case where I'll use a itty-bitty cursor (or a while loop) of perhaps most dozens of rows (as opposed to the millions I'm targeting). Thus, I'm still working in (partitioned sub) sets, but my retrieval runs faster.
Of course, an even faster solution would be to call the partioned input domains in parallel from outside, but that introduces an interaction will an external system, and when "good enough" speed can be achieved by looping in serial, just may not be worth it (epecially during development).
I've got plenty of cases where rows from a configuration table have to be read and code generated and executed, or in many meta-programming scenarios.
There are also cases when cursors simply outperform because the optimizer is not smart enough. In those cases, either there is meta-information in your head which is simply not revealed to the optimizer through the indexes or statistics on the tables, or the code is just so complicated that the joins (and usually, re-joins) simply can't be optimized in the way you can visualize them in a cursor-based fashion. In SQL Server 2005, I believe CTEs tend to make this look a lot simpler in the code, but whether the optimizer also sees them as simpler is hard to know - it comes down to comparing the execution plan to how you think it could be done most efficiently and making the call.
General rule - don't use a cursor unless necessary. But when necessary, don't give yourself a hard time about it.
In a pure SQL environment, I'd rather avoid cursors as you suggest. But once you cross over into procedural language (like PL/SQL), there are a number of uses. For example, if you want to retrieve certain rows and want "to do" something more complex than update it with them.
If a table is un-indexed for some reason, a cursor will be faster than other methods of iterating over a table. I found this information in this blog post on cursors in SQL Server last year.
While the author is in favor of "use only as a last resort" approach (as is everyone here), she does find a case or two where cursors perform as well as other available alternatives (including the running totals pointed out by Robert Rossney). Among other interesting points she makes, she indicates that cursors operate more efficiently inside stored procedures than as ad-hoc queries. The author also does an excellent job of pointing out when the performance problems we all associate with cursors begin to occur.
The blog post contains actual code, so readers can try the queries themselves and see the results.
Very occasionally you will get an operation that needs a cursor but in T-SQL it is fairly rare. Identity(int) columns or sequences order things in ways within set operations. Aggregations where calculations might change at certain points (such as accumulating claims from ground up to a limit or excess point) are inherently procedural, so those are a candidate for a cursor.
Other candidates would be inherently procedural such as looping through a configuration table and generating and executing a series of queries.
There are lots of different cursor behaviors.
You should never use a cursor unless you can explain all of these options and which ones are on by default.
And so, I never do.
Instead, when I feel the urge to loop over something in T-SQL... I load it into a variable table, which is something like a LOCAL STATIC SCROLL cursor... except that it can be indexed and joined (edit: and the downside of preventing the use of parallelism).
Sure, there are a number of places where cursors might be better than set-based operations.
One is if you're updating a lot of data in a table (for example a SQL Agent job to pre-compute data on a schedule) then you might use cursors to do it in multiple small sets rather than one large one to reduce the amount of concurrent locking and thus reduce the chance of lock contention and/or deadlocks with other processes accessing the data.
Another is if you want to take application-level locks using the
sp_getapplock
stored procedure, which is useful when you want to ensure rows that are being polled for by multiple processes are retrieved exactly once (example here).In general though, I'd agree that it's best to start using set based operations if possible, and only move to cursors if required either for functionality or performance reasons (with evidence to back the latter up).