|
|
|
SSC-Enthusiastic
      
Group: General Forum Members
Last Login: Friday, October 23, 2009 8:02 AM
Points: 197,
Visits: 67
|
|
|
|
|
|
Forum Newbie
      
Group: General Forum Members
Last Login: Wednesday, June 03, 2009 6:23 AM
Points: 4,
Visits: 32
|
|
Using non-deterministic functions like ROW_NUMBER and NEWID need to be done carefully - my blog article: http://sqlblogcasts.com/blogs/tonyrogerson/archive/2008/06/12/bug-in-inline-expansion-of-non-deterministic-functions-in-derived-tables-and-cte-s-causes-incorrect-results.aspx explains the serious bug that exists in SQL Server 2005 with using them.
Tony.
|
|
|
|
|
SSC-Enthusiastic
      
Group: General Forum Members
Last Login: Tuesday, November 03, 2009 1:48 AM
Points: 113,
Visits: 109
|
|
And if you're using SQLServer2000, then you'll need to use a "TOP n" correlated subquery, since ROW_NUMBER() is not available.. eg:
select RecentVersion.* from (select distinct ProductId from dbo.ProductVersion) ProductList inner join dbo.ProductVersion RecentVersion on RecentVersion.ProductId = ProductList.ProductId and cast(RecentVersion.Version as varchar(10)) + '.' + cast(RecentVersion.MinorVersion as varchar(10)) + '.' + cast(RecentVersion.ReleaseVersion as varchar(10)) = ( select top 1 cast(x.Version as varchar(10)) + '.' + cast(x.MinorVersion as varchar(10)) + '.' + cast(x.ReleaseVersion as varchar(10)) from dbo.ProductVersion x where x.ProductId = RecentVersion.ProductId order by x.Version desc, x.MinorVersion desc, x.ReleaseVersion desc )
|
|
|
|
|
SSC Veteran
      
Group: General Forum Members
Last Login: Friday, October 30, 2009 9:01 AM
Points: 287,
Visits: 356
|
|
|
|
|
|
SSC Rookie
      
Group: General Forum Members
Last Login: 2 days ago @ 8:58 AM
Points: 26,
Visits: 97
|
|
| Great Article - thank you
|
|
|
|
|
SSC Journeyman
      
Group: General Forum Members
Last Login: Wednesday, October 28, 2009 6:49 AM
Points: 81,
Visits: 36
|
|
Nice example!
Alternativly you could use a cursor to make it more readable and improve performance over a nested query. That said i dont like cursors and do prefer common table expressions!
SET ROWCOUNT 0 go
IF OBJECT_ID('tempdb..#ProductVersion') IS NULL BEGIN CREATE TABLE #ProductVersion ( ProductID int NOT NULL, Version int NOT NULL, MinorVersion int NOT NULL, ReleaseVersion int NOT NULL, StandardCost numeric(30, 4) NOT NULL ) END
DECLARE @ProductId INT DECLARE A CURSOR FOR SELECT ProductId FROM ProductVersion GROUP BY ProductId ORDER BY ProductId OPEN A FETCH NEXT FROM A INTO @ProductId WHILE @@FETCH_STATUS = 0 BEGIN INSERT INTO #ProductVersion SELECT TOP 1 ProductId, Version, MinorVersion, ReleaseVersion, StandardCost FROM ProductVersion WHERE ProductId = @ProductId ORDER BY ProductId ASC, Version DESC, MinorVersion DESC, ReleaseVersion DESC
FETCH NEXT FROM A INTO @ProductId END CLOSE A DEALLOCATE A
SELECT * FROM #ProductVersion DROP TABLE #ProductVersion
|
|
|
|
|
SSC-Enthusiastic
      
Group: General Forum Members
Last Login: Wednesday, October 28, 2009 12:24 PM
Points: 126,
Visits: 77
|
|
Thanks for the great article - I thought that you did a good job of explaining how to use the row_number function and comparing its performance to subqueries.
Tim
|
|
|
|
|
Forum Newbie
      
Group: General Forum Members
Last Login: Thursday, July 30, 2009 10:48 AM
Points: 3,
Visits: 72
|
|
How could I leverage this to get, say, the "most current" version of a contract (i.e., either the contract currently in effect or the latest contract even if it was expired) *and* the latest version of the contract (i.e., it doesn't take effect until the future? I have a query using subqueries for this that looks something like this (this is simplified a bit). The row_number() query is much more concise but only returns that max contract date for each contract, which leaves out the current dates for those that have them:
SELECT DISTINCT group_number ,subgroup_number ,ISNULL( (SELECT MAX(contract_thru_date) FROM contracts curr1 WHERE curr1.group_number=curr.group_number AND GETDATE() BETWEEN contract_from_date AND contract_thru_date ,(SELECT MAX(contract_thru_date) FROM contracts prev WHERE prev.group_number=curr.group_number ) ) contract_thru_date FROM contracts curr
EDIT: NM, I figured it out. All I had to was add an or statement to the where in the CTE. Great article, came at a good time! 
|
|
|
|
|
SSC-Enthusiastic
      
Group: General Forum Members
Last Login: 2 days ago @ 12:50 PM
Points: 188,
Visits: 1,485
|
|
Well done article.
Question: I hate to open a can of worms on a different topic, but I'm so curious as to why you specified the nolock hint for the row_number version of the query. Do you know of specific problems that require use of nolock for this type of implementation?
Thanks.
|
|
|
|
|
SSCrazy Eights
        
Group: General Forum Members
Last Login: 2 days ago @ 4:56 PM
Points: 8,401,
Visits: 7,821
|
|
tony rogerson (5/12/2009) Using non-deterministic functions like ROW_NUMBER and NEWID need to be done carefully - my blog article: http://sqlblogcasts.com/blogs/tonyrogerson/archive/2008/06/12/bug-in-inline-expansion-of-non-deterministic-functions-in-derived-tables-and-cte-s-causes-incorrect-results.aspx explains the serious bug that exists in SQL Server 2005 with using them. Afraid that I do not understand this. AFAIK, CTEs are table expressions like non-indexed views. If you write them non-deterministically (which is what you do in your blog article), then they return non-deterministic results. And if you reference a non-deterministic table expression multiple times, you are not guaranteed to get the same results. That's straight ANSI SQL to the best of my knowledge and I see no bug in Transact-SQL demonstrated here.
And as far as ROW_NUMBER() it only returns non-deterministic results if the OVER clause parameters are non-deterministic. If you use a deterministic ORDER BY (which also requires that the column set is uniquely orderable), then you will get deterministic results.
All this really demonstrates is that if you input non-deterministic expressions without instantiating them, then you will get non-deterministic results back. Garbage In, Garbage Out.
-- RBarryYoung, (302)375-0451 blog: MovingSQL.com, Twitter: @RBarryYoung Proactive Performance Solutions, Inc. "Performance is our middle name."
|
|
|
|