2016-04-07 43 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'的元组。 –