2010-08-16 83 views
2

大家好, 我有一些困難,通過聚集在SQL Server瞭解背後組的理由2005年SQL組(簡單的問題/ SQL服務器2005)

我有以下查詢,工作正常並返回每個contact.id一行和事件的第一occurence

SELECT 
contact.id 
,MIN(eve.date_created) 
FROM _contact contact WITH(nolock) 
INNER JOIN table2 tb2 WITH (nolock) ON contact.id = tb2.id1 
INNER JOIN _event eve WITH (nolock) ON tb2.id2 = eve.id 
INNER JOIN _cashtable cash WITH (nolock) ON cash.contact_id = contact.id 
GROUP BY contact.id 

但是我正在尋找的是有以下查詢,仍然只有每contact.id拉出一排

SELECT 
contact.id 
,MIN(eve.date_created) 
,cash.id2 -- the cash linked to the first event 
,eve.id  -- the first event linked to the contact  
FROM _contact contact with (nolock) 
INNER JOIN _table2 tb2 WITH (nolock) ON contact.id = tb2.id1 
INNER JOIN _event eve WITH (nolock) ON tb2.id2 = eve.id 
INNER JOIN _cashtable cash WITH (nolock) ON cash.contact_id = contact.id 
GROUP BY contact.id 

我收到標準錯誤消息,說我需要將cash.id2和eve.id添加到group by子句中,這會返回我不想要的結果。

我知道有使用等級()/分區 甚至包括

select(MIN(eve.date_created) 

FROM子句中的潛在選擇,但我不知道這將是最好的把這個和我仍然相當困惑,爲什麼SQL要求一切都包含在組聲明,所以任何建議將是偉大的:)

在此先感謝!

回答

2

我認爲你需要一個子查詢與本身只返回分鐘(事件日期)的聚合上加入事件表

SELECT 
contact.id,min_created,cash.id2 -- the cash linked to the first event 
,eve.id  -- the first event linked to the contact  
FROM _contact contact 
INNER JOIN _table2 tb2 ON contact.id = tb2.id1 
INNER JOIN _event eve ON tb2.id2 = eve.id 
inner join (select id, date_created as min_created from _event group by id) eve_min 
on eve_min.id = eve.id and eve_min.min_created = eve.date_created 
INNER JOIN _cashtable cash ON cash.contact_id = contact.id 
+0

謝謝你,我假設內部聯接(選擇id,date_created實際上是選擇MIN(date_created)?當使用它它返回許多行每個contact_id(約50),而不是一個,有沒有原因是什麼?(如果它有助於使用選擇不同的一半行數返回到每個聯繫人大約25) – Dibstar 2010-08-17 08:59:14

+0

是的,你是對的,我應該應用min()函數date_created。 如果它返回更多如果有多於一個的min_created或現金,如果每個ID有多個行,則它會從事件中獲取剩餘的行。 – Beth 2010-08-17 14:57:17

0

假設對於條目的插入和鏈接邏輯沒有任何奇怪的變化,您可以爲事件和現金兩者選擇最小ID,它應該是每個項目中最早的。

另一種方法是向連接添加子句以將其限制爲第一個或最小ID,那麼您將不需要分組。

+0

這樣做的問題是,(對於沒有被更具體的道歉),現金.id2是實際現金價值的文本參考,因此將MIN()應用於它將返回錯誤 – Dibstar 2010-08-16 15:13:46

+0

該ID仍然是一個純數字值嗎?如果是這樣,轉換爲int不會在事物的方案中增加太多開銷,然後可以選擇MIN值。 不是最理想的情況,但它仍然有效。儘管在連接之外進行轉換(意味着聚合函數),但比在連接內進行轉換要便宜得多。因此,請在選擇內的ID上進行轉換。 MIN(CONVERT(INT,cash.id2)) – 2010-08-16 15:26:36

+0

不是,所有的ID字段都是nvarchar(s),包含數字和字母的混合,因此推測不能有效地轉換爲整數用於排名或MIN/MAX函數? – Dibstar 2010-08-16 15:31:35

0

您不應該需要將它們添加到group-by子句中,但是您確實需要以某種方式對它們進行聚合。分組從句的要點是您需要一組統計信息。也就是說,您希望爲同一聯繫人ID創建所有內容,而不僅僅是第一個記錄。

我相信,如果你這樣做

SELECT Contact.Id, 
    MIN(eve.date_created), 
    MAX(eve.date_created), //this will get you the range of events 
    SUM(cash.id2), //total cash for all events 
    MIN(eve.Id), //First event id 
    MAX(eve.Id) //Latest event id 
FROM _contact Contact //Etc. etc. 

您的查詢將進行分組工作。它似乎像什麼,你想要的,但是,更像是:

[Select your columns] 
FROM _contact Contact 
INNER JOIN _Table2 tb2 on contact.id = tb2.id1 
    and tb2.id1 = (Select MIN(id2) from tb2 where tb2.id1 = contact.id) 
INNER JOIN _event eve on tb2.Id2 = eve.id 
INNER JOIN _cashtable cahs on cash.contact_id = contact.id 
    and cash.id = (select MIN(id) from cash where cash.contact_id = contact.id) 

情況因人而異,和我你的表結構將部分地決定如何快,運行(也就是,你可能想看看一些優化)。此外,我從記憶中完全做到了這一點,所以你可能需要與那些INNER JOIN一起玩,才能讓他們工作。這裏的要點是,你並沒有試圖抓住團體,你試圖抓住每個contact.id的第一個。

+0

感謝您的支持,不幸的是,cash.id2字段是一個文本字段,因此應用MIN()約束會引發錯誤。對於這個表,我需要取出與MIN(eve.date_created)值直接相關的cash.id2 - 是否有一種方法可以簡單地檢索已分配的值,而無需將其添加到group子句中?謝謝:) – Dibstar 2010-08-16 15:16:50