2010-01-26 10 views
24

Tôi có biểu thức bảng chung rất béo, bao gồm số hàng để tôi có thể trả lại tập kết quả được phân trang. Tôi cũng muốn trả lại tổng số bản ghi phù hợp với truy vấn trước khi tôi đặt trang kết quả.Làm thế nào để tham khảo một CTE hai lần?

with recs as (select *, row_number() over (order by id) as rownum from ......) 
select * from recs where rownum between @a and @b .... select count(*) from recs 

Rõ ràng truy vấn của tôi ở trên là chắp vá, nhưng nó chỉ để minh họa quan điểm của tôi. Tôi muốn một trang kết quả VÀ tổng số trận đấu. Làm thế nào để làm điều này mà không cần phải sao chép và dán toàn bộ 20 dòng CTE?

+3

Tôi có thể xem xét đổi tên câu hỏi này vì câu trả lời được chấp nhận không thực sự sử dụng CTE hai lần. –

Trả lời

15

Bạn có thể sử dụng dấu phẩy để tạo nhiều CTE tham chiếu đến CTE ở trên.

Chỉ để minh họa những gì tôi muốn nói:

with recs as (
select 
    *, 
    row_number() over (order by id) as rownum from ...... 
    ), 
counts as (
    select count(*) as totalrows from recs 
) 
select recs.*,count.totalrows 
from recs 
cross apply counts 
where rownum between @a and @b .... 

Đây không phải là một giải pháp tốt.

Giải pháp tốt nhất mà tôi thấy có tổng số trong CTE mà không tính các bản ghi được mô tả trong this article.

DECLARE @startRow INT; SET @startrow = 50; 
WITH cols 
AS 
(
    SELECT table_name, column_name, 
     ROW_NUMBER() OVER(ORDER BY table_name, column_name) AS seq, 
     ROW_NUMBER() OVER(ORDER BY table_name DESC, column_name desc) AS totrows 
    FROM [INFORMATION_SCHEMA].columns 
) 
SELECT table_name, column_name, totrows + seq -1 as TotRows 
FROM cols 
WHERE seq BETWEEN @startRow AND @startRow + 49 
ORDERBY seq 
+0

Vâng tôi nghĩ về điều này, nhưng có một vấn đề khi truy vấn trả về không có hồ sơ. Tôi đoán tôi có thể fudge nó với một UNION ALL và một hàng giả ... –

+0

Kiểm tra đoạn mã cuối cùng tôi lấy từ bài báo. Nó có một số hàng tăng dần và giảm dần và nó chỉ thêm chúng trong các kết quả để có được tổng số hàng. Điều này thực sự thực sự tốt trong môi trường sản xuất của chúng tôi. –

+1

Ahh rực rỡ! Liên kết đó có một cách thực sự tốt để đạt được điều này. –

19

Đừng nghĩ rằng bạn có thể. Từ MSDN

Một biểu thức bảng chung (CTE) có thể nghĩ đến như là kết quả tạm thời thiết lập được định nghĩa trong phạm vi thực hiện của một đơn SELECT, INSERT, UPDATE, DELETE, hoặc CREATE VIEW tuyên bố.

Nhấn mạnh vào "một câu lệnh SELECT, INSERT, UPDATE, DELETE hoặc CREATE VIEW."

Đây có thể là trường hợp bạn muốn sử dụng Temporary Table.

CREATE TABLE #Recs 
{ 
    ..... 
} 
INSERT INTO #Recs 
select *, row_number() over (order by id) as rownum from ...... 

Nếu bạn không biết cấu trúc của bảng trước khi tay bạn có thể sử dụng hình thức này để tạo ra một bảng tạm thời:

select *, row_number() over (order by id) as rownum INTO #Recs from ...... 

Bạn sẽ có thể sử dụng bảng tạm thời theo cách thức bạn đã mô tả ở trên.

+1

Ngoài ra, tôi khuyên bạn chỉ nên sử dụng những "SELECT *" nếu bạn thật sự cần chúng. Chúng có thể gây ra các vấn đề về hiệu năng và hầu hết thời gian không thực sự cần thiết. –

+0

Cú pháp này để tạo bảng tạm thời cũng có thể hữu ích: Chọn * Thành #Recs Từ ... –

+0

Thực ra tôi có một câu lệnh SELECT phức tạp mà tôi cần làm trên dữ liệu phân cấp và cách thức mà nó được gọi sẽ khác nhau tùy thuộc vào tình huống. –

4

Bạn có thể thêm một lĩnh vực có tổng hàng trong đó, tất nhiên nó sẽ được trên mỗi hàng

select recs.*,totalrows = (select count(0) from recs) 
from recs 
1

này là tốt nhất:

;WITH recs AS 
(SELECT a,b,c, 
     row_number() over (
         ORDER BY id) AS RowNum, 
        row_number() over() AS RecordCount 
FROM ......) 
SELECT a,b,c,rownum,RecordCount FROM recs 
WHERE rownum BETWEEN @a AND @b 
1

Đây là cách chúng tôi đối phó với phân trang (không có quản lý phiên cho bây giờ) trong một môi trường sản xuất. Thực hiện như mong đợi.

DECLARE 
    @p_PageNumberRequested int = 1, 
     -- Provide -1 to retreive all pages with all the rows. 
    @p_RowsPerPage   int = 25 

;WITH Numbered AS (
SELECT 
    ROW_NUMBER() OVER (ORDER BY YourOrdering) AbsoluteRowNumber 
, COUNT(1) OVER() TotalRows 
, YourColumns 
FROM 
    YourTable 
), 
Paged AS (
SELECT 
    (AbsoluteRowNumber - 1)/@p_RowsPerPage + 1 PageNumber, 
    * 
FROM 
    Numbered) 
SELECT 
    ROW_NUMBER() OVER(PARTITION BY PageNumber ORDER BY AbsoluteRowNumber) RowNumberOnPage, 
    * 
FROM 
    Paged 
WHERE 
     PageNumber = @p_PageNumberRequested 
    OR 
     @p_PageNumberRequested = -1 
ORDER BY 
    AbsoluteRowNumber