2016-04-07 63 views
0

我試圖在我的數據庫中獲得符合某些條件的6個月實體趨勢,但問題是我需要嵌套幾個級別來確定實體是否合格。嵌套查詢時對結果進行分組

實體是可能有多個「帳戶」的「成員」,我需要確保他們的帳戶在包含它們之前都沒有設置某些標誌。

如果我想只是得到一個數作爲一個特定日期的(我們保持歷史數據),我會做這樣的事情:

SELECT COUNT(sup.SSN) 
FROM MemberSuppTable as sup 
WHERE (
    sup.ProcessDate = @PROCESSDATE 
    AND sup.MemberSuppID IN (
    SELECT summ.MemberSuppID 
    FROM MemberSummaryTable as summ 
    WHERE (
     summ.ProcessDate = @PROCESSDATE 
     AND summ.AccountNumber IN (
     SELECT acct.AccountNumber 
     FROM AccountTable as acct 
     WHERE ( 
      acct.ProcessDate = @PROCESSDATE 
      --other criteria for account exclusion go here. 
     ) 
    ) 
    ) 
) 
) 

MemberSuppTable對成員高級別信息:

(ID, FirstAccountOpenDate, status, etc) 

MemberSummaryTable關係到賬戶中的成員MemberSuppTable

(AccountNumber, MemberSuppID, ...) 

現在,我試圖獲得月末處理日期的計數,按單個查詢中的處理日期分組。

所以,在上面的查詢將返回

ssn count 
---------- 
1,000,000 

我想:

process date | ssn count 
------------------------ 
20160430  | 8,000,000 
20160551  | 8,500,000 
...   | ... 
20160331  | 1,000,000 

到目前爲止,我想出了以下(見下文,爲什麼它不」 t工作):

WITH valid_dates AS (
    SELECT D.ProcessDate 
    FROM arcu.vwARCUProcessDates AS D 
    WHERE d.FullDate = D.MonthEndDate 
    AND d.ProcessDate >= @SDATE 
) 


SELECT sup.ProcessDate, COUNT(DISTINCT sup.SSN) 
FROM MemberSuppTable as sup 
WHERE (
    AND sup.ProcessDate IN (SELECT * FROM valid_dates)  
    AND sup.MemberSuppID IN (
    SELECT summ.MemberSuppID 
    FROM MemberSummaryTable as summ 
    WHERE (
     summ.ProcessDate IN (SELECT * FROM valid_dates) 
     AND summ.AccountNumber IN (
     SELECT acct.AccountNumber 
     FROM AccountTable as acct 
     WHERE ( 
      acct.ProcessDate IN (SELECT * FROM valid_dates) 
      ... 
     ) 
    ) 
    ) 
) 
) 
GROUP BY (sup.ProcessDate) 

隨着上述但是我相信,如果一個成員與valid_dates表中的ANY進程日期的條件匹配,那麼它將包含在所有組中。

任何人都可以幫我嗎? (我是SQL新手,如果我遺漏了一些簡單的東西,請原諒我。)

+0

包含示例數據和期望結果。 [**如何創建一個最小,完整和可驗證的示例**](http://stackoverflow.com/help/mcve) –

+0

期望的結果是在問題的中間......你是說你想要的精確的表格? – LukeP

+1

好像你正在使用許多'IN()'語句,改變它們加入它會更容易閱讀和理解,並且可能會更有效。 – sagi

回答

1

首先,我會使用重寫第一個查詢INNER JOIN代替WHERE .. IN

SELECT COUNT(DISTINCT sup.SSN) 
FROM MemberSuppTable as sup 
INNER JOIN MemberSummaryTable AS summ 
    ON summ.MemberSuppID = sup.MemberSuppID 
INNER JOIN AccountTable AS acct 
    ON acct.AccountNumber = summ.AccountNumber 
WHERE sup.ProcessDate = @PROCESSDATE 
    AND summ.ProcessDate = @PROCESSDATE 
    AND acct.ProcessDate = @PROCESSDATE 
    -- other criteria for account exclusion go here. 

這看起來更緊湊,是(IMHO)更具有可讀性。

現在我想更改查詢的方式,即@PROCESSDATE occures只有一次

SELECT COUNT(DISTINCT sup.SSN) 
FROM MemberSuppTable as sup 
INNER JOIN MemberSummaryTable AS summ 
    ON summ.MemberSuppID = sup.MemberSuppID 
INNER JOIN AccountTable AS acct 
    ON acct.AccountNumber = summ.AccountNumber 
WHERE sup.ProcessDate = @PROCESSDATE 
    AND summ.ProcessDate = sup.ProcessDate 
    AND acct.ProcessDate = sup.ProcessDate 
    -- other criteria for account exclusion go here. 

你可以保持WHERE子句中的條件,但我更喜歡他們是ON子句中

SELECT COUNT(DISTINCT sup.SSN) 
FROM MemberSuppTable AS sup 
INNER JOIN MemberSummaryTable AS summ 
    ON summ.MemberSuppID = sup.MemberSuppID 
    AND summ.ProcessDate = sup.ProcessDate 
INNER JOIN AccountTable AS acct 
    ON acct.AccountNumber = summ.AccountNumber 
    AND acct.ProcessDate = sup.ProcessDate 
WHERE sup.ProcessDate = @PROCESSDATE 
    -- other criteria for account exclusion go here. 

現在很容易得到COUNT每個ProcessDate

SELECT sup.ProcessDate, COUNT(DISTINCT sup.SSN) 
FROM MemberSuppTable as sup 
INNER JOIN MemberSummaryTable AS summ 
    ON summ.MemberSuppID = sup.MemberSuppID 
    AND summ.ProcessDate = sup.ProcessDate 
INNER JOIN AccountTable AS acct 
    ON acct.AccountNumber = summ.AccountNumber 
    AND acct.ProcessDate = sup.ProcessDate 
-- WHERE criteria for account exclusion go here. 
GROUP BY sup.ProcessDate 

要還「valid_dates」過濾器,將只是一個額外JOIN和一些WHERE條件

SELECT sup.ProcessDate, COUNT(DISTINCT sup.SSN) 
FROM MemberSuppTable as sup 
INNER JOIN MemberSummaryTable AS summ 
    ON summ.MemberSuppID = sup.MemberSuppID 
    AND summ.ProcessDate = sup.ProcessDate 
INNER JOIN AccountTable AS acct 
    ON acct.AccountNumber = summ.AccountNumber 
    AND acct.ProcessDate = sup.ProcessDate 
INNER JOIN arcu.vwARCUProcessDates AS d 
    ON d.ProcessDate = sup.ProcessDate 
WHERE d.FullDate = d.MonthEndDate 
    AND d.ProcessDate >= @SDATE 
    -- AND criteria for account exclusion go here. 
GROUP BY sup.ProcessDate 

爲了獲得更好的性能,可能會更好GROUP BY d.ProcessDate,但不要忘了也ajust的SELECT部分。

編輯: 正如在評論中指出,DISTINCT關鍵字必須使用,如果要計算一次每SSN事呢。所以我編輯瞭解決方案。

還必須注意的是,即使使用DISTINCT,第一個查詢也不等同於原始查詢。如果sup.SSN不唯一,則查詢可能會返回不同的結果。

+0

由於成員摘要表和membersupp表之間存在多對一關係,因此這會導致比我想要返回的結果更多的結果。兩者之間的內部連接爲會員所擁有的每個帳戶創建一個單獨的行,我只需要一個。 (可以計數(DISTINCT ssn),但我想知道是否有另一種方式) – LukeP

+0

如果'DISTINCT'由於某種原因不適合您 - 請查看我對Thorsten Kettners的回答。 –

+0

由於OP要計算每個日期的不同SSN,所以必須使用COUNT(DISTINCT sup.SSN)'。如果它不是獨特的SSNs OP要計數,那麼這個查詢甚至不會工作,因爲每個MemberSuppTable記錄可能有許多MemberSummaryTable和AccountTable條目,你會得到你的計數倍增。這就是爲什麼在檢查是否存在時總是應該使用'IN'或'EXISTS'。該查詢按照原樣提供,不僅錯誤,而且可讀性也較差,因爲它給人的感覺是對SSN的計數。 –

1

IN子句對於這樣的查詢來說是非常好的。比聯接更具可讀性,因爲您可以清楚地顯示從哪個表中選擇數據以及哪些表只能訪問以檢查記錄是否存在。這是很好的結構,並顯示你給了一些想法的查詢。

但是,如果沒有不必要的別名和括號,查詢會變得更具可讀性。

不管怎樣,你要使用你的子查詢發現相同過程日期,我想,所以相應地提高你的IN子句:

select processdate, count(distinct ssn) 
from membersupptable 
where (processdate, membersuppid) in 
(
    select processdate, membersuppid 
    from membersummarytable 
    where (processdate, accountnumber) in 
    (
    select processdate, accountnumber 
    from accounttable 
    where processdate in 
    (
     select processdate 
     from vwarcuprocessdates 
     where fulldate = monthenddate 
     and processdate >= @sdate 
    ) 
) 
) 
group by processdate; 
+0

我意識到我不小心把它標記爲mysql,但我真的使用tsql。當我嘗試做一個多列WHERE IN時,它對我大喊大叫。 – LukeP

+0

@LukeP,如果「多列凡在」不工作,你可以嘗試使用派生子查詢像'那裏membersuppid在( 從membersummarytable 選擇membersuppid 其中processdate = sup.processdate 和... )'。但是您需要爲表格別名或使用其全名。 –

+0

@LukeP:然後你應該使用相關的子查詢,就像Paul所說的那樣,但是使用'EXISTS'而不是'IN'。這更可讀,因爲我們預計'EXISTS'子句與外部查詢和IN子句不相關。可惜SQL Server不支持帶'IN'的元組。 –