2010-07-29 46 views
17

Tôi đang viết các procs được lưu trữ đang được gọi bởi hệ thống cũ. Một trong những ràng buộc của hệ thống kế thừa là phải có ít nhất một hàng trong tập kết quả đơn được trả về từ proc được lưu trữ. Tiêu chuẩn là trả về số không trong cột đầu tiên (vâng, tôi biết!). Cách rõ ràng để đạt được điều này là tạo ra một bảng tạm thời, đặt kết quả vào nó, kiểm tra cho bất kỳ hàng nào trong bảng tạm thời và trả về kết quả từ bảng tạm thời hoặc kết quả trống duy nhất.Thêm hàng trống vào kết quả truy vấn nếu không tìm thấy kết quả

Một cách khác có thể là thực hiện một EXISTS dựa vào cùng một mệnh đề where trong truy vấn chính trước khi truy vấn chính được thực hiện.

Cả hai điều này đều không thỏa mãn. Bất cứ ai có thể nghĩ ra một cách tốt hơn. Tôi đã suy nghĩ xuống theo dòng của một UNION loại như thế này (Tôi biết điều này không làm việc):

--create table #test 
--(
-- id int identity, 
-- category varchar(10) 
--) 
--go 
--insert #test values ('A') 
--insert #test values ('B') 
--insert #test values ('C') 

declare @category varchar(10) 

set @category = 'D' 

select 
    id, category 
from #test 
where category = @category 
union 
select 
    0, '' 
from #test 
where @@rowcount = 0 
+1

Cân nhắc xem xét câu trả lời được chấp nhận sau khi đọc giải pháp @ swe! Thật tốt khi tôi thừa nhận tôi cảm thấy muốn thôi thúc bạn ở đây;) http: // stackoverflow.com/a/32586119/2979473 – ensisNoctis

+0

@ensisNoctis trừ khi tôi bị nhầm lẫn, giải pháp đó sẽ chỉ hoạt động trong các tình huống mà bạn mong đợi hoặc là 0 hoặc một kết quả trở lại –

+1

Vui lòng, bạn vui lòng cho phép tôi chia sẻ với bạn mã này hiện tại đang được sản xuất trong công ty của tôi, tất cả nhờ vào StackOverflow;) Không thể phù hợp với tất cả trong nhận xét này, vì vậy tôi đã đăng một câu trả lời khác, nhưng vẫn là @ swe, chỉ được định dạng tốt hơn. http://stackoverflow.com/a/37046650/2979473 Nó trả về các hàng từ bảng mong muốn nếu chúng tồn tại (bất kỳ số nào> = 1), nếu không các hàng từ một bảng khác (hoặc chữ, như trong ví dụ của tôi). – ensisNoctis

Trả lời

10

Đó là một câu hỏi cũ, nhưng tôi đã có cùng một vấn đề. Giải pháp là thực sự đơn giản KHÔNG đôi chọn:

select top(1) WITH TIES * FROM (
select 
id, category, 1 as orderdummy 
from #test 
where category = @category 
union select 0, '', 2) ORDER BY orderdummy 

bởi "có quan hệ" bạn sẽ có được tất cả các hàng (tất cả đều có 1 là "orderdummy", vì vậy tất cả là mối quan hệ), hoặc nếu không có kết quả, bạn lấy tiền mặc định của bạn.

+0

Điều này thật tuyệt vời! Đơn giản, nhanh chóng và tốt hơn so với câu trả lời được chấp nhận ở chỗ nó không sử dụng bảng tạm thời, không truy vấn kép cũng không khai báo biến (vì vậy nó có thể dễ dàng được sử dụng trong các TVF nội tuyến)! – ensisNoctis

0

Tôi đoán bạn có thể thử:

Declare @count int 
set @count = 0 

Begin 
Select @count = Count([Column]) 
From //Your query 

if(@Count = 0) 
    select 0 
else //run your query 

Nhược điểm là bạn đang chạy truy vấn của bạn một cách hiệu quả hai lần, mặt lên là bạn đang bỏ qua bảng tạm thời.

+0

Đây là một phương pháp tương tự với câu lệnh EXISTS mà tôi đã đề xuất trong câu hỏi. Sự khác biệt là số đếm kém hiệu quả hơn một chút. –

27

Rất ít tùy chọn tôi sợ.

Bạn luôn phải chạm bàn hai lần, cho dù COUNT, EXISTS trước, tồn tại trong UNION, TOP khoản vv

select 
    id, category 
from mytable 
where category = @category 
union all --edit, of course it's quicker 
select 
    0, '' 
where NOT EXISTS (SELECT * FROM mytable where category = @category) 

Một EXISTS giải pháp là tốt hơn sau đó đếm bởi vì nó sẽ dừng lại khi nó tìm thấy một hàng. COUNT sẽ duyệt qua tất cả các hàng để thực sự đếm chúng

+0

Có một chút thông tin mới cho tôi lại: EXISTS dừng khi tìm thấy hàng. Cảm ơn @gbn! –

+0

+1: WITH/TOP của tôi không trả về hàng giả khi WITH không có bất kỳ dữ liệu nào. –

+0

Vâng, tôi chắc chắn thích sử dụng EXISTS vì nó nhanh hơn. Nó chỉ là một sự xấu hổ mà tôi phải viết cùng một mệnh đề where hai lần. Hãy suy nghĩ tôi có lẽ sẽ kết thúc đi cho điều này mặc dù, cảm ơn. –

2

Bạn có thể sử dụng kết hợp bên ngoài đầy đủ. Một cái gì đó có hiệu lực của ...

declare @category varchar(10) 

set @category = 'D' 

select #test.id, ISNULL(#test.category, @category) as category from (
    select 
     id, category 
    from #test 
    where category = @category 
) 
FULL OUTER JOIN (Select @category as CategoryHelper) as EmptyHelper on 1=1 

Hiện tại, thử nghiệm này không thể chắc chắn về loại tác động này nhưng nó sẽ cho bạn một hàng trống với Danh mục dân cư.

+0

Đó là một giải pháp thực sự thú vị mà tránh viết mệnh đề where hai lần. Tôi muốn được biết liệu điều này có hiệu quả không và chi phí hiệu suất là bao nhiêu? Tôi không thể tìm ra lý do tại sao bạn bọc truy vấn chính trong bảng dẫn xuất. Điều này có cần thiết không? –

+0

Gói truy vấn chính là do mệnh đề where nhưng có thể được viết lại tùy thuộc vào cách bạn đang cấu trúc truy vấn cơ bản. Bạn không tham gia vào khu vực chính xác (sau khi lọc), sau đó tiêu chí có thể áp dụng cho cả hai bảng. Chi phí dường như là tối thiểu (0% trong kế hoạch thực hiện thực tế) tuy nhiên truy vấn tôi có là khá phức tạp trong hoạt động của nó. –

+0

Có, điều đó có ý nghĩa hơn bây giờ bạn đã bao gồm các isnull. Cảm ơn –

0

Để tránh trùng lặp truy vấn chọn, trước tiên bảng khoảng nhiệt độ lưu trữ kết quả truy vấn như thế nào? Và dựa trên bảng tạm thời, trả về hàng mặc định nếu bảng tạm thời trống hoặc trả lại temp khi nó có kết quả?

1

Đây là câu trả lời của @ swe, chỉ được định dạng tốt hơn.

CREATE FUNCTION [mail].[f_GetRecipients] 
(
    @MailContentCode VARCHAR(50) 
) 
RETURNS TABLE 
AS 
RETURN 
(
    SELECT TOP 1 WITH TIES -- returns all rows having highest priority found 
     [To], 
     CC, 
     BCC 
    FROM (
     SELECT 
      [To], 
      CC, 
      BCC, 
      1 AS Priority -- if no rows, priority 2 under UNION will get returned 
     FROM mail.Recipients 
     WHERE 1 = 1 
      AND IsActive = 1 
      AND MailContentCode = @MailContentCode 

     UNION ALL 

     SELECT 
      * 
     FROM (VALUES 
      (N'[email protected]', NULL, NULL, 2), 
      (N'[email protected]', NULL, NULL, 2) 
     ) defaults([To], CC, BCC, Priority) 
    ) emails 
    ORDER BY Priority 
) 
Các vấn đề liên quan