连接多个表并在TSQL中获取Count数据

时间:2016-02-24 06:23:56

标签: sql-server tsql join

我有三张桌子需要加入。我可以加入其中两个并获得所需的结果,这个结果表需要与另一个表连接。

表1

+----------+---------+------+
| Username | Country | Team |
+----------+---------+------+
| abc      | US      | New  |
| abc      | CAN     | New  |
| bcd      | US      | Old  |
+----------+---------+------+

表2

+----------+-------------+----------+------------+
| Username | CompanyCode | Document | Entry Date |
+----------+-------------+----------+------------+
| abc      |           1 |      112 | 24/06/2014 |
| abc      |           2 |      123 | 24/06/2014 |
| bcd      |           3 |      456 | 24/06/2014 |
| efg      |           4 |      984 | 24/06/2014 |
+----------+-------------+----------+------------+

我写了以下代码..

SELECT Username, CompanyCode, Document, IIF(MONTH([Entry Date]) = 6 AND YEAR([Entry Date]) = 2014, 'TRUE', 'FALSE') AS [Posted], 
       COALESCE(tNew.Country, 'not there') AS DC, COALESCE(tNew.Team, 'not there') AS Team FROM Table2
OUTER APPLY
    (
        SELECT TOP 1 Country, Team FROM Table1
        WHERE Table1.[Username] = Table2.[Username]
    ) tNew

...导致( Table99 )......

+----------+--------------+----------+------------+--------+-----------+-----------+
| Username | Company Code | Document | Entry Date | Posted |  Country  |   Team    |
+----------+--------------+----------+------------+--------+-----------+-----------+
| abc      |            1 |      112 | 24/06/2014 | TRUE   | US        | New       |
| abc      |            2 |      123 | 24/06/2014 | TRUE   | US        | New       |
| bcd      |            3 |      456 | 24/06/2014 | TRUE   | US        | Old       |
| efg      |            4 |      984 | 24/06/2014 | TRUE   | not there | not there |
+----------+--------------+----------+------------+--------+-----------+-----------+

现在我有另一张桌子, Table3

+--------------+--------------+
| Company Code | Company Name |
+--------------+--------------+
|            1 | MS           |
|            2 | APL          |
|            3 | GOO          |
|            4 | IBM          |
|            5 | AMZ          |
+--------------+--------------+

我想在Company Code上将Table99与Table3一起加入,Document WHERE Posted = TRUE AND Country <> 'not there'的计数结果为......

+--------------+--------------+-----------------+
| Company Code | Company Name | Total Documents |
+--------------+--------------+-----------------+
|            1 | MS           |               1 |
|            2 | APL          |               1 |
|            3 | GOO          |               1 |
|            4 | IBM          |               0 |
|            5 | AMZ          |               0 |
+--------------+--------------+-----------------+

3 个答案:

答案 0 :(得分:2)

LEFT JOIN上执行Table3和原始查询,然后使用条件SUM来计算:

SELECT
    t3.CompanyCode,
    t3.CompanyName,
    SUM(CASE WHEN t.Posted = 'TRUE' AND t.Country <> 'not there' THEN 1 ELSE 0 END)
FROM Table3 t3
LEFT JOIN (
    SELECT 
        Username, 
        CompanyCode, 
        Document,
        tnew.Country, 
        IIF(MONTH(EntryDate) = 6 AND YEAR(EntryDate) = 2014, 'TRUE', 'FALSE') AS [Posted], 
        COALESCE(tNew.Country, 'not there') AS DC,
        COALESCE(tNew.Team, 'not there') AS Team
    FROM Table2
    OUTER APPLY(
        SELECT TOP 1 Country, Team FROM Table1
        WHERE Table1.[Username] = Table2.[Username]
    ) tNew
) t
    ON t3.CompanyCode = t.CompanyCode
GROUP BY t3.CompanyCode, t3.CompanyName
ORDER BY t3.CompanyCode

TRY IT HERE

答案 1 :(得分:1)

您可以将派生表视为真实表格来处理:

SELECT Username, Table2.CompanyCode, Document, IIF(MONTH([Entry Date]) = 6 AND YEAR([Entry Date]) = 2014, 'TRUE', 'FALSE') AS [Posted], 
       COALESCE(tNew.Country, 'not there') AS DC, COALESCE(tNew.Team, 'not there') AS Team FROM Table2
OUTER APPLY
    (
        SELECT TOP 1 Country, Team FROM Table1
        WHERE Table1.[Username] = Table2.[Username]
    ) tNew

    JOIN Table3 ON Table2.CompanyCode = Table3.CompanyCode

答案 2 :(得分:1)

我认为你的查询过于复杂了。 SQL的APPLY运算符主要用于表值函数。更一般地说,它在两个表之间有用whenever there is no simple join condition

在您的情况下,有一个非常简单的连接条件 - UsernameTable1中的Table2列。连接是SQL的本质,并且(通常)应该是您需要组合来自多个表的信息时的第一个调用端口。

所以在这种情况下,考虑到你需要实现的最终结果,你可以简单地使用两个左连接,没有APPLY

with PostedDocs as (
    -- Define your requirements on the EntryDate value here
    select  CompanyCode
            ,Username
            ,Document
    from    Table2
    where   MONTH(EntryDate) = 6 
    and     YEAR(EntryDate) = 2014
    )
select      CO.CompanyCode
            ,CO.CompanyName
            ,TotalDocuments =count(distinct case when USR.Country is null then null else DOC.Document end) 

from        Table3      CO
left join   PostedDocs  DOC on CO.CompanyCode=DOC.CompanyCode
left join   Table1      USR on DOC.Username=USR.Username

group by    CO.CompanyCode
            ,CO.CompanyName
order by    CompanyCode asc

这为您在问题中提供的输入提供了所需的结果。它是一种更加面向SQL的思维方式,可能在大型表格上表现更好。

请注意,我以<{1}}开始。这样做是有道理的,因为在最终结果集中,您希望Table3中的每一行都有一行。 Table3使结果集更大,重复left joins行,但随后我将其与Table3重新汇总。

group by函数不包含count值,您可以在此处利用:左边连接不成功,值为null,所以有无需转换为“不存在”等值。

一些切向点

  • 通常在SQL中,我们不在列名中使用空格。我的答案与您的问题的列名略有不同,因为我将空格用于使列名更容易使用。

  • 像我一样(DOC,USR,CO)给表格提供有意义的别名会很有帮助。

  • 在原始代码中,此处:

    null

    除非包含OUTER APPLY ( SELECT TOP 1 Country, Team FROM Table1 WHERE Table1.[Username] = Table2.[Username] ) tNew 子句,否则您应该知道SQL Server不保证一致的结果排序。因此,如果您继续使用这段代码,那么在将来的某个时刻,用户ORDER BY返回的TOP 1行可能是加拿大版,而不是美国版。我不确定这对你是否重要,但它可能很重要。一般来说,如果您关心一致的结果,那么使用abc是不好的做法。您应该订购结果,或者使用TOP 1DISTINCT功能,如果这些功能更适合您的情况。