2009-09-25 5 views
7

Hy vọng này là tầm thường cho một SQL-Ninja ... Được cố gắng để có được làm việc truy vấn sau đây:Sử dụng bảng xếp hạng năng có nguồn gốc cột trong mệnh đề where (SQL Server 2008)

này là dành cho SQL Server 2008

SELECT 
    ROW_NUMBER() OVER (ORDER BY Date_Time DESC) AS RowNumber, * 
FROM 
    (SELECT 
     T.A_ID, T.User_Name, T.Date_Time, T.Value, 
     U.ID, U.Name, U.Field1, U.Field2, 
     COUNT(U.ID) OVER() AS TotalRows 
    FROM 
     TeeTable as T 
    INNER JOIN 
     YouTable AS U ON T.U_ID = U.ID 
    WHERE 
     T.Value BETWEEN 222 AND 225) Filtered 
WHERE 
    RowNumber BETWEEN 1 AND 5 

Giá trị được phần nào giả tạo để đưa ra một ví dụ cụ thể, nhưng tinh thần của truy vấn được giữ nguyên hoàn toàn. Lỗi tôi nhận được từ tuyên bố này là:

Tên cột không hợp lệ 'RowNumber'.

Nếu tôi xóa mệnh đề WHERE cuối cùng (RowNumber BETWEEN ...), nó trả về tập kết quả mong đợi (A_ID, User_Name, Date_Time vv ...), với RowNumber dưới dạng cột (có giá trị nhạy cảm) các kết quả. Tuy nhiên, tôi không thể so sánh với nó trong mệnh đề WHERE. Tôi rõ ràng đang làm điều gì đó ngu ngốc nhưng điều này đạt đến giới hạn SQL của tôi!

Tôi đã cố gắng sắp xếp lại vị trí này dưới dạng CTE, (VỚI AS được lọc ...) nhưng kết quả cuối cùng cũng giống nhau, có vẻ như đó chỉ là đường cho những gì tôi đã làm.

Ý tưởng? Làm cách nào để lọc cột RowNumber?

+0

Tránh thẻ 'mssql' vì nó dễ bị nhầm lẫn với' mysql' –

Trả lời

15

Bạn phải di chuyển toán tử WHERE lên trên danh sách dự án nơi cột RowNumber được tạo. Sử dụng một bảng có nguồn gốc hoặc một CTE:

SELECT * 
    FROM (
    SELECT *, ROW_NUMBER() OVER (...) as RowNumber 
    FROM ...) As ... 
WHERE RowNumber = ... 

CTE tương đương là:

WITH cte AS (
SELECT *, ROW_NUMBER() OVER (...) as RowNumber 
     FROM ...) 
SELECT * FROM cte 
WHERE RowNumber = ... 
+0

Làm việc tuyệt vời, cảm ơn! –

3

Các chức năng Window (trong đó ROW_NUMBER là bí quyết tốt nhất) được điền vào rất muộn trong truy vấn, cũng sau mệnh đề WHERE. Do đó, bạn cũng phải lồng ghép nó, để lọc nó:

SELECT * 
FROM (
    SELECT ROW_NUMBER() OVER (ORDER BY Date_Time DESC) AS RowNumber, * 
    FROM 
    (SELECT T.A_ID, T.User_Name, T.Date_Time, T.Value, 
      U.ID, U.Name, U.Field1, U.Field2, 
      COUNT(U.ID) OVER() AS TotalRows 
     FROM 
     TeeTable as T INNER JOIN YouTable AS U 
     ON T.U_ID = U.ID 
     WHERE T.Value BETWEEN 222 AND 225 
    ) Numbered 
) Filtered 
WHERE RowNumber BETWEEN 1 AND 5 

Bạn cũng có thể đặt chúng trong CTE hoặc Chế độ xem để có hiệu ứng tương tự.

+0

Không thể chấp nhận 2 câu trả lời, nhưng tôi sẽ upvote ya. :) Cảm ơn! –

0

Sự cố với Truy vấn xuất hiện do lỗi trong thứ tự xử lý lôgic. Đây là thứ tự xử lý hợp lý được chỉ định trong MSDN dev Network.

Thứ tự xử lý lôgic của câu lệnh SELECT Các bước sau hiển thị thứ tự xử lý lôgic hoặc thứ tự ràng buộc cho câu lệnh SELECT. Thứ tự này xác định khi các đối tượng được xác định trong một bước được tạo sẵn cho các mệnh đề trong các bước tiếp theo. Ví dụ, nếu bộ xử lý truy vấn có thể liên kết với (truy cập) các bảng hoặc khung nhìn được định nghĩa trong mệnh đề FROM, các đối tượng này và các cột của chúng được tạo sẵn cho tất cả các bước tiếp theo. Ngược lại, vì mệnh đề SELECT là bước 8, bất kỳ bí danh cột hoặc cột có nguồn gốc nào được xác định trong mệnh đề đó không thể được tham chiếu bởi các mệnh đề trước đó. Tuy nhiên, chúng có thể được tham chiếu bởi các mệnh đề tiếp theo như mệnh đề ORDER BY. Lưu ý rằng việc thực thi vật lý thực tế của câu lệnh được xác định bởi bộ xử lý truy vấn và thứ tự có thể thay đổi từ danh sách này. TỪ ON THAM GIA ĐÂU GROUP BY VỚI CUBE hoặc VỚI ROLLUP CÓ CHỌN DISTINCT ORDER BY TOP

Vì vậy, giới thiệu các chức năng xếp hạng như một bí danh trong subquery trong từ phần và sau đó bạn sẽ có thể đặt điều kiện trên bí danh trong phần vị trí.

Chúc may mắn .. !!