Cách hiệu quả nhất để trả về nhiều tập hợp trong một Proc được lưu trữ?


7

Cách tốt nhất hoặc hiệu quả nhất để có được nhiều giá trị kết quả tổng hợp là gì?

Về cơ bản, tôi có một ứng dụng email và muốn nhận tất cả số lượng tin nhắn cho từng loại thư mục (hộp thư đến, đã gửi, lưu trữ, gắn cờ ...) như được định nghĩa dưới đây.

Đây là một ví dụ về những điều tôi đang cố gắng thực hiện trong một cuộc gọi Proc được lưu trữ. (trong đó [uid] là ID người dùng)

SELECT * FROM Message
Inbox    WHERE [to]    = [uid] 
Unread    WHERE [to]    = [uid] and isread = 0
Flagged    WHERE [to]    = [uid] and isFlagged = 1
Drafts    WHERE [to]    = [uid] and isDraft = 1
Sent Messages    WHERE [from] = [uid]
Archived Messages    WHERE [to]     = [uid] and isArchived = 1

Câu trả lời:


7

COUNT..CASE là cách thông thường. Đối với "Đã gửi" mặc dù nó phức tạp hơn một chút vì đó là bộ lọc uid khác nhau yêu cầu 2 truy vấn trên bảng Tin nhắn

Tôi đã sử dụng cấu trúc này để cho phép hàng 0 cho / từ. Nó tránh OR hoặc thêm bộ lọc uid vào mỗi CASE.

Mỗi bảng dẫn xuất (có thể viết dưới dạng CTE) sẽ chỉ trả về một hàng và tôi đã sử dụng MAX trên uid để tránh NHÓM B BYNG trong trường hợp có ai thắc mắc

SELECT
    ISNULL(M.Inbox, 0) AS Inbox,
    ISNULL(M.Unread, 0) AS Unread,
    ISNULL(M.Flagged, 0) AS Flagged,
    ISNULL(M.Drafts, 0) AS Drafts,
    ISNULL(S.Sent, 0) AS Sent,
    ISNULL(M.Archived, 0) AS Archived
FROM
    (
    SELECT
        COUNT(*) AS InBox,
        COUNT(CASE WHEN isread = 0 THEN 1 ELSE NULL END) Unread,
        COUNT(CASE WHEN isFlagged = 1 THEN 1 ELSE NULL END) Flagged,
        COUNT(CASE WHEN isDraft = 1 THEN 1 ELSE NULL END) Drafts,
        S.Sent,
        COUNT(CASE WHEN isArchived = 0 THEN 1 ELSE NULL END) Archived
    FROM
        Message
    WHERE
        [to] = [uid] 
    ) M
    FULL OUTER JOIN
    (
    SELECT COUNT(*) AS Sent
    FROM Message
    WHERE [from] = [uid]
    ) S ON 1=1

Biên tập:

Một tổng hợp không có GROUP BY sẽ luôn trả về kết quả (xem SO tại đây ). Tôi đã quên điều đó.

Tôi đã cập nhật SQL của mình


vâng, tôi đoán rằng người được gửi là một cây gậy trong phát ngôn ... Tôi đã suy nghĩ nhiều hơn về những gì @Cape Cod Gunny đăng. nhưng tôi không chắc chắn nếu nhiều lựa chọn tốt hơn hay xấu hơn mà toàn bộ tham gia bên ngoài bạn đã đăng. suy nghĩ?
kacal vật liệu

2
@kacalacco: đây là 2 truy vấn của bảng và một câu lệnh. Câu trả lời khác là 6 truy vấn và một số câu lệnh. Ngay cả khi lập chỉ mục, nó hoạt động ít hơn 66% theo các thuật ngữ đơn giản
gbn

@gbn - tại sao không bỏ joinuidđồ đạc và sử dụng a cross join?
Jack nói hãy thử topanswers.xyz

@JackPDoureb: Tôi đã xem xét điều đó. Nhưng nếu không có tin nhắn đã gửi hoặc không có tin nhắn hộp thư đến, bạn sẽ không nhận được kết quả. MAX chỉ để tránh NHÓM THEO (sẽ hữu ích cho nhiều giá trị uid). (Tôi đã chỉnh sửa nhận xét này BTW trong trường hợp bạn đọc trước đó)
gbn

1
@JackPDoureb: Tôi cho rằng sẽ có ít nhất một tin nhắn ở bất cứ đâu. Như chúng ta biết, giả định là mẹ của tất cả các feckup :-). Tôi đã có 1 = 1 nhưng bị xóa vì quá mờ. À, OP có rất nhiều ý tưởng về những bình luận này ngay bây giờ ... Chúc mừng
gbn

2
DECLARE @Inbox  bigint
DECLARE @Unread bigint
DECLARE @Flagged bigint
/*
MORE DECLARE STATEMENTS GO HERE
*/

SET @Inbox   = SELECT Count(*) FROM MESSAGE WHERE [to] = [uid] 
SET @Unread  = SELECT Count(*) FROM MESSAGE WHERE [to] = [uid] and isread = 0
SET @Flagged = SELECT Count(*) FROM MESSAGE WHERE [to] = [uid] and isFlagged = 1

/*
MORE SELECT STATEMENTS GO HERE
*/

SELECT
@Inbox   as Inbox,
@Unread  as Unread,
@Flagged as Flagged

/*
MORE @Variables GO HERE
*/
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.