2011-08-27 136 views
1

最近我遇到了一個奇怪的問題。我有兩個簡單的查詢,其中一個使用TOP X,另一個使用ROW_NUMBER執行相同的操作,然後選擇1到X之間的rowNumber,並且它們都按同一列排序,但結果完全不同。TOP X和Row_Number之間的區別()

例如,假設我們有一個簡單的數據庫,如下面的一些虛擬數據:

CREATE TABLE [dbo].[Test](
[Id] [int] IDENTITY(1,1) NOT NULL, 
[NDate] [datetime] NOT NULL, 
CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED 
(
[Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
SET IDENTITY_INSERT [dbo].[Test] ON 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (1, '2011-08-24 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (2, '2011-08-24 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (3, '2011-08-24 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (4, '2011-08-24 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (5, '2011-08-21 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (6, '2011-08-21 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (7, '2011-08-21 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (8, '2011-08-21 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (9, '2011-08-21 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (10, '2011-08-21 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (11, '2011-08-21 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (12, '2011-08-21 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (13, '2011-08-21 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (14, '2011-08-21 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (15, '2011-08-21 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (16, '2011-08-21 00:00:00.000') 
SET IDENTITY_INSERT [dbo].[Test] OFF 

現在,如果我們執行下面的查詢,我們會得到不同的結果。如果我們使用TOP 10中,我們會得到下面的結果:

SELECT TOP 10 [Id],[NDate] FROM [Test] order by NDate desc 
RESULT=> 
Id NDate 
4 2011-08-24 00:00:00.000 
3 2011-08-24 00:00:00.000 
2 2011-08-24 00:00:00.000 
1 2011-08-24 00:00:00.000 
11 2011-08-21 00:00:00.000 
10 2011-08-21 00:00:00.000 
9 2011-08-21 00:00:00.000 
8 2011-08-21 00:00:00.000 
7 2011-08-21 00:00:00.000 
6 2011-08-21 00:00:00.000 


select id,NDate from (
    select ROW_NUMBER() over (order by NDate DESC) as RNumber, Id,NDate 
    from Test) as t 
where RNumber between 1 and 10 
RESULT=> 
id NDate 
1 2011-08-24 00:00:00.000 
2 2011-08-24 00:00:00.000 
3 2011-08-24 00:00:00.000 
4 2011-08-24 00:00:00.000 
5 2011-08-21 00:00:00.000 
6 2011-08-21 00:00:00.000 
7 2011-08-21 00:00:00.000 
8 2011-08-21 00:00:00.000 
9 2011-08-21 00:00:00.000 
10 2011-08-21 00:00:00.000 

的問題是,當你使用LINQ to SQL,並且要選擇第一頁將是TOP X進行分頁,生成的查詢,而對於其他頁面將使用ROW_NUMBER,結果是,一些項目將永遠不會出現在列表中。

回答

4

您需要實施二級排序。

例子:

select id,NDate from (
    select ROW_NUMBER() over (order by NDate DESC, id) as RNumber, Id,NDate -- Note: NDate DESC, id 
    from Test) as t 
where RNumber between 1 and 10 

例子:

SELECT TOP 10 [Id],[NDate] FROM [Test] order by NDate desc, ID -- Note: NDate DESC, id 

否則,你可能也希望每一個獨立NDate隨機記錄。

如果要爲每個查詢記錄相同的記錄,則必須指定該輔助排序列。

+0

你也應該有ORDER BY上的第一個例子的外部查詢。不管你有什麼經驗,都不會保證它會出現與ROW_NUMBER()中相同的排序。 +1都一樣。 – MatBailie

1

我同意@ hamlin11,但是把它更簡單:-)

在你被

order by NDate desc 
/* to get same results as example 2, change this to 
    order by NDate desc, id 
*/ 

,並在第二次排序的第一個例子通過

order by NDate DESC, id 

在第二個示例是按ID排序的,這就是爲什麼ID列是按順序排列的,在第一個示例中沒有這樣做。

這可能是更好地使用數據這樣的,這樣你就可以更清楚地看到發生了什麼:

/****** Object: Table [dbo].[Test] Script Date: 08/27/2011 07:56:29 ******/ 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
CREATE TABLE [dbo].[Test](
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [NDate] [datetime] NOT NULL, 
CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
GO 
SET IDENTITY_INSERT [dbo].[Test] ON 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (1, '2011-08-10 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (2, '2011-08-11 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (3, '2011-08-12 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (4, '2011-08-13 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (5, '2011-08-14 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (6, '2011-08-15 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (7, '2011-08-16 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (8, '2011-08-31 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (9, '2011-08-30 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (10, '2011-08-29 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (11, '2011-08-28 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (12, '2011-08-27 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (13, '2011-08-26 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (14, '2011-08-25 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (15, '2011-08-24 00:00:00.000') 
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (16, '2011-08-23 00:00:00.000') 
SET IDENTITY_INSERT [dbo].[Test] OFF 
+0

我想說測試數據應該包含相同日期的條目,因爲它是OP的問題的二階排序。 – MatBailie

+0

@Dems我知道他*想*按ID列排序,但我試圖證明他實際上是按日期列排序的:-) – inspite