2008-10-23 24 views
7

'daki ROW_NUMBER() OVER() yöntemini kullanarak farklı sütunlarda sıralama kullanarak sorgulama yapalım. Northwind veritabanını kullanıyorum ve sorguyu, diğer parametrelerle birlikte içeren bir saklı yordamla çalıştırmak istiyorum. aşağıdaki: sayfalandırma başladığıSQL Server 2005

  • @Offset sıralama amaçlı kullanılan sütun belirtmek için,
  • @Limit
  • sayfa boyutunu belirtmek için,
  • @SortColumn belirtmek için,
  • @SortDirection, yükselen veya soyundan gelen sıralamayı belirtmek için. önbelleğe alma bir seçenek değildir bu yüzden sonuç kümesi (IMO, berbat ve ViewState kullanarak bile, kabul edilmez) satırları binlerce içerdiğinden

fikir veritabanı üzerinde sayfalama yapmaktır. SQL Server 2005 Bildiğiniz gibi

her bölüm ilk satır için 1'den başlayan bir sonuç kümesinin bir bölüm içinde üst üste sıralı numarasını döndüren fonksiyonu ROW_NUMBER sağlar.

Her döndürülmüş sütunda sıralama yapmalıyız (bu örnekte beş tane) ve dinamik SQL bir seçenek değildir, bu yüzden iki seçeneğimiz vardır: IF ... ELSE ... bol ve 10 sorguya sahip olmak, korumak için bir cehennemdir, veya bir aşağıdaki gibi sorgusu:

WITH PaginatedOrders AS (
    SELECT 
     CASE (@SortColumn + ':' + @SortDirection) 
      WHEN 'OrderID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID ASC) 
      WHEN 'OrderID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID DESC) 
      WHEN 'CustomerID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.CustomerID ASC) 
      WHEN 'CustomerID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.CustomerID DESC) 
      WHEN 'EmployeeID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.EmployeeID ASC) 
      WHEN 'EmployeeID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.EmployeeID DESC) 
      WHEN 'OrderDate:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderDate ASC) 
      WHEN 'OrderDate:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderDate DESC) 
      WHEN 'ShippedDate:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID ASC) 
      WHEN 'ShippedDate:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID DESC) 
     END AS RowNumber, 
     OrderID, CustomerID, EmployeeID, OrderDate, ShippedDate 
    FROM Orders 
    -- WHERE clause goes here 
) 
SELECT 
    RowNumber, OrderID, CustomerID, EmployeeID, OrderDate, ShippedDate, 
    @Offset, @Limit, @SortColumn, @SortDirection 
FROM PaginatedOrders 
WHERE RowNumber BETWEEN @Offset AND (@Offset + @Limit - 1) 
ORDER BY RowNumber 

farklı argümanlarla, sorgu birkaç kez denedim, ve performans aslında oldukça iyidir, ama susturur o başka bir şekilde optimize edilebilir gibi görünüyor.

Bu sorguda bir sorun var mı, yoksa bu şekilde mi yaparsınız? Farklı bir yaklaşım mı önerirsiniz?

+0

Benim için aptalca bir hata düzeltildi. Lütfen tekrar deneyin. – Tomalak

cevap

6

basit: ASC sırası tersi seçilir, ya da, bu NULL (TANIM) üzerinde sıralanır

SELECT 
    OrderID, CustomerID, EmployeeID, OrderDate, ShippedDate, 
    @Offset, @Limit, @SortColumn, @SortDirection 
FROM 
    Orders 
WHERE 
    ROW_NUMBER() OVER 
    (
    ORDER BY 
     /* same expression as in the ORDER BY of the whole query */ 
) BETWEEN (@PageNum - 1) * @PageSize + 1 AND @PageNum * @PageSize 
    /* AND more conditions ... */ 
ORDER BY 
    CASE WHEN @SortDirection = 'A' THEN 
    CASE @SortColumn 
     WHEN 'OrderID' THEN OrderID 
     WHEN 'CustomerID' THEN CustomerID 
     /* more... */ 
    END 
    END, 
    CASE WHEN @SortDirection = 'D' THEN 
    CASE @SortColumn 
     WHEN 'OrderID' THEN OrderID 
     WHEN 'CustomerID' THEN CustomerID 
     /* more... */ 
    END 
    END DESC 

.

ROW_NUMBER() işlevi, aynı SİPARİŞ BY ifadesi üzerinde çalışsın.

+0

Bu öğleden sonra ben sadece ben sonuçları karşılaştırmak için sorgu planlayıcısı ve profiler ile bu işlevi ile çalışacağız :) –

+0

Ben sonuçları görmek için sabırsızlanıyorum. :-) – Tomalak

+0

Tam olarak bu, aşağıdaki hatayı verir: 'Msg 207, Düzey 16, Durum 1, Satır 41 - Geçersiz sütun adı 'RowNumber'. O zaman bir WITH cümleciğini kullanacağım. –

İlgili konular