2009-06-17 36 views
0

使用SQL Server 2005我試圖根據case語句與子查詢分組,但是我收到一個錯誤(「每個GROUP BY表達式必須至少包含一個列引用。「 」)。我可以很容易地解決它,但任何人都可以解釋錯誤嗎?我有一個對#header.header的列引用。使用子查詢分組時SQL Server 2005錯誤

create table #header (header int) 
create table #detail (header int, detail int) 

insert into #header values (1) 
insert into #header values (2) 
insert into #header values (3) 

insert into #detail values (1, 1) 
insert into #detail values (2, 1) 

--error: Each GROUP BY expression must contain at least one column reference. 
select case when exists (select 1 from #detail where #detail.header = #header.header) then 1 else 0 end hasrecords from #header 
group by case when exists (select 1 from #detail where #detail.header = #header.header) then 1 else 0 end 

--results I want 
select hasrecords, count(*) from 
(
    select case when exists (select 1 from #detail where #detail.header = #header.header) then 1 else 0 end hasrecords from #header 
) hasrecords 
group by hasrecords 

drop table #header 
drop table #detail 

[編輯]注意(在響應評論)相關和不相關的子查詢:當你需要給它一個實際的列

--correlated 
select header, case when exists (select 1 from #detail where #detail.header = #header.header) then 1 else 0 end hasrecords from #header 

--non-correlated 
select #header.header, case when count(#detail.header) > 0 then 1 else 0 end hasrecords from #header left join #detail on #header.header = #detail.header group by #header.header 
+0

分組由1和0是沒有問題: 選擇情況下,當報頭= 1,則1個否則爲0結束headeris1,通過情況下,從組的#header COUNT(*)當頭部= 1,則1否則0結束 這是存在的,造成它,但我不明白爲什麼它應該。 (愚蠢)重寫下面的錯誤:一個子查詢不能用於一個表達式的組中。 選擇1 =時的情況(從#header b中選擇top 1 header,其中b.header = a.header)then 1 else 0 end headeris1,count from(*)from #header group by 1 =(select top 1來自#header b的頭,其中b.header = a.header)then 1 else 0 end 爲什麼我不能在一個組中使用子查詢? – 2009-06-17 15:18:26

+0

真正的問題是爲什麼在你身上使用相關的子查詢呢?他們可能是性能殺手,並且聯接通常會更好,所以爲什麼不開始使用聯接,並且如果無法聯接工作(我從未見過這種聯接的實例,您的里程可能會有所不同),則只使用相關聯的子查詢。作爲一個規則,當有多種方式來做某事時,你絕不應該從最壞的方式開始。 – HLGEM 2009-06-17 20:22:57

+0

我使用了相關的子查詢,因爲這似乎邏輯上反映了我想要做的最好的事情 - 對於每個標題,查看是否存在任何記錄,而不用擔心有多少。我不清楚爲什麼相關的子查詢必然會變差。作爲測試,我在問題的底部添加了一些查詢。查看執行計劃,與相關子查詢相比,使用聯接的執行計劃的查詢成本爲73%,查詢成本爲27%。存在將在#detail上保存表掃描。我可能是錯的,但在本例中似乎相關的子查詢表現更好。 – 2009-06-18 09:09:00

回答

3

首先,如果我們給予充分的錯誤,應爲「每個GROUP BY表達式必須至少包含一個列,它是不是一個外參考。

理解的錯誤,我們需要澄清由‘外部參考’

是什麼意思

(注:在這種情況下,沒有任何與內部或外部連接)

是參照主查詢和它的子查詢。 在這種情況下是EXISTS子查詢,這是一個相關子查詢,因爲它具有的#header.header外部引用,其被引用的外部表#header,而到#detail任何參考將被視爲內部引用。

因此,本質上,因爲CASE利用引用外部查詢的相關子查詢,則會觸發錯誤狀態,因爲當您嘗試僅使用GROUP BY子句中被解釋爲外部的表達式時出現此錯誤消息引用。

子查詢可以用於GROUP BY,但不是相關的子查詢。

混淆,可以由非subqueried,更簡單的諸如

select 
case when header=1 then 1 
     else 0 
end headeris1, 
'constant' 
from #header 
group by case when header=1 then 1 else 0 end , 'constant' 

或甚至與一個@variable

清除泥漿代替恆定查詢來產生相同的錯誤?

千電子伏

0

您通過1或0它告訴給組按(標題)分組,而不是值。

所以,如果我的理解正確,你想要一個頭的列表和他們的詳細記錄計數?

這可能適合你嗎?

SELECT DISTINCT h.header, COUNT(d.detail) AS detail_count 
FROM #header AS h 
LEFT JOIN #detail AS d ON d.header = h.header 
GROUP BY h.header, d.detail 

有了這樣的結果......

header detail_count 
1  1 
2  1 
3  0