【问题标题】:Joining multiple Tables and getting Count data in TSQL连接多个表并在 SQL 中获取 Count 数据
【发布时间】:2016-06-06 07:20:28
【问题描述】:

我有三个需要连接的表。我能够加入其中两个并获得所需的结果,而这个结果表需要与另一个表连接。

表 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 |
+--------------+--------------+-----------------+

【问题讨论】:

  • Table1 中用户abc 的两条记录中,为什么您对Country=US 的一条感兴趣,而不是Country=CAN 的一条?是什么“业务逻辑”使它成为重要的记录?
  • 好问题斯图尔特。一个用户可能支持多个国家。我很想知道用户是否存在于我的 Table1 中,而不是他/她支持哪个国家/地区。
  • 啊好。我的回答是基于这个假设:-)

标签: sql-server tsql join


【解决方案1】:

Table3 和原始查询执行LEFT JOIN,然后使用条件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

【讨论】:

    【解决方案2】:

    您可以像处理真实表一样处理派生表:

    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
    

    【讨论】:

    • 谢谢。但我无法让这个工作,因为 tNew(基本上是 Table1)没有 [公司代码]。如何加入 Table2 的【公司代码】?
    • 抱歉,tNew.CompanyCode 应该是 Table2.CompanyCode
    【解决方案3】:

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

    不过,在您的情况下,有一个非常简单的连接条件 - Table1Table2 中的 Username 列。联接是 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 的思维方式,并且可能在大型表上表现更好。

    请注意,我开始Table3。这样做是有意义的,因为在您的最终结果集中,您希望Table3 中的每一行对应一行。 left joins 使结果集更大,复制了Table3 行,但随后我将它们与group by 聚合在一起。

    count 函数不包含 null 值,您可以在这里利用它:左连接不成功的地方,值将是 null,因此无需转换为值比如“不存在”。

    几个切线点

    • 通常在 SQL 中,我们不在列名中使用空格。我的回答与您的问题的列名略有不同,因为我去掉了空格以便更容易使用列名。

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

    • 在您的原始代码中,此处:

      OUTER APPLY
      (
          SELECT TOP 1 Country, Team FROM Table1
          WHERE Table1.[Username] = Table2.[Username]
      ) tNew
      

      您应该知道,除非您包含 ORDER BY 子句,否则 SQL Server 不保证结果顺序一致。因此,如果您继续使用这段代码,那么在将来的某个时候,为用户 abc 返回的 TOP 1 行可能是加拿大的,而不是美国的。我完全不确定这对你是否重要,但它可能很重要。一般来说,如果您关心一致的结果,那么像这样使用TOP 1 是不好的做法。您应该订购结果,或者使用DISTINCTrow_number() 函数,如果它们更适合您的情况。

    【讨论】:

      猜你喜欢
      • 2021-04-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-25
      • 1970-01-01
      相关资源
      最近更新 更多