【问题标题】:TSQL Grouping and selecting count of rows from sub queryTSQL分组并从子查询中选择行数
【发布时间】:2020-10-07 16:25:36
【问题描述】:

我有下表

AccountID   Name
1           Foo Bar
2           Jon Dow

AccountID   AddressLine         City
1           123 Test RD         New York
1           456 Test RD         New York
2           Lombard Street      San Francisco
2           Lombard Street      San Francisco

对于给定的 AccountID,我想选择 AddressLine 和 City。
如果帐户具有相同的AddressLine,则应选择该 AddressLine 值,否则返回“多个”。
如果帐户具有相同的City,则应选择该城市值,否则返回“多个”。

例如,对于帐户 ID 1,查询应该返回

AccountID  AddressLine City
1          Multiple    New York

这里是SQLFiddle

以下是我的查询(不工作)。我认为问题是从子查询中分组和选择计数

SELECT
    A.AccountID,
    CASE
        WHEN T1.CNT = 1
            THEN T1.AddressLine
        ELSE 'Multiple'
    END AS 'Address Line',
    CASE WHEN T2.CNT = 1
        THEN T2.City
    ELSE 'Multiple'
    END AS 'City'   
FROM Accounts A
INNER JOIN
(
    SELECT 
        ad.AccountID,
        COUNT(DISTINCT(ad.AccountID)) AS CNT,
        ad.AddressLine
    FROM Addresses ad   
    GROUP BY ad.AccountID, ad.AddressLine
) T1 ON T1.AccountID = A.AccountID
INNER JOIN
(
    SELECT 
        ad.AccountID,
        COUNT(DISTINCT(ad.AccountID)) AS CNT,
        ad.City
    FROM Addresses ad   
    GROUP BY ad.AccountID, ad.City
) T2
ON T2.AccountID = A.AccountID
WHERE 
    a.AccountID = 1

【问题讨论】:

    标签: sql-server tsql sql-server-2012 sql-server-2017


    【解决方案1】:

    我认为应该这样做。我使用string_agg 函数来汇总组中的地址,因为您只想在存在单个值时显示该值。我放弃了 where 谓词,只显示一个帐户,但添加回来很简单。

    ;with dist
    as
    (
      SELECT DISTINCT
      AccountID
      ,AddressLine
      ,City
      FROM addresses
    )
    ,agg
    as
    (
    SELECT 
      AccountID
      ,COUNT(*) as AddressCount
      ,STRING_AGG(AddressLine, ',') as Address
      ,STRING_AGG(City, ',') as City
    FROM dist 
    GROUP BY AccountID
    )
    
    select 
    AccountID
    ,CASE AddressCount 
      WHEN 0 THEN 'N/A'
      WHEN 1 THEN Address
      ELSE 'Multiple' END as Address
    ,CASE AddressCount 
      WHEN 0 THEN 'N/A'
      WHEN 1 THEN City
      ELSE 'Multiple' END as City
    from agg
    

    【讨论】:

      【解决方案2】:

      这是一个可以在 SSMS 中运行的简单示例:

      DECLARE @Accounts TABLE ( AccountID INT, Name VARCHAR(50) );
      INSERT INTO @Accounts ( AccountID, Name ) 
          VALUES ( 1, 'Foo Bar' ), ( 2, 'Jon Dow' );
      
      DECLARE @Addresses TABLE ( AccountID INT, AddressLine VARCHAR(50), City VARCHAR(50) );
      INSERT INTO @Addresses ( AccountID, AddressLine, City )
          VALUES ( 1, '123 Test Rd', 'New York' ), ( 1, '456 Test Rd', 'New York' ), ( 2, 'Lombard Street', 'San Francisco' ), ( 2, 'Lombard Street', 'San Francisco' );
      
      SELECT
          Accounts.AccountID,
          AddressRecords.AddressLine,
          Addresses.City
      FROM @Accounts AS Accounts
      INNER JOIN @Addresses AS Addresses
          ON Accounts.AccountID = Addresses.AccountID
      OUTER APPLY (
      
          SELECT CASE
              WHEN ( SELECT COUNT ( DISTINCT ( x.AddressLine ) ) FROM @Addresses AS x WHERE x.AccountID = Accounts.AccountID ) > 1 THEN 'Multiple'
              ELSE ( SELECT DISTINCT AddressLine FROM @Addresses AS x WHERE x.AccountID = Accounts.AccountID )
          END AS AddressLine
      
      ) AS AddressRecords
      WHERE
          Accounts.AccountID = 1
      GROUP BY
          Accounts.AccountID, AddressRecords.AddressLine, Addresses.City;
      

      AccountID 1 返回

      +-----------+-------------+----------+
      | AccountID | AddressLine |   City   |
      +-----------+-------------+----------+
      |         1 | Multiple    | New York |
      +-----------+-------------+----------+
      

      AccountID 2 返回

      +-----------+----------------+---------------+
      | AccountID |  AddressLine   |     City      |
      +-----------+----------------+---------------+
      |         2 | Lombard Street | San Francisco |
      +-----------+----------------+---------------+
      

      当然,这并没有考虑到多个城市值的可能性。

      【讨论】:

        【解决方案3】:

        还不如把我的也加进去。它并不比其他任何人都好,但无论如何都在这里......

        SELECT
            A.AccountID,
            T1.AddressLine,
            T2.City
        FROM Accounts A
        INNER JOIN
        (
            SELECT 
                ad.AccountID,
                CASE WHEN COUNT(DISTINCT(ad.AddressLine)) > 1 THEN 'Multiple' ELSE MIN(ad.AddressLine) END AS AddressLine
            FROM Addresses ad   
            GROUP BY ad.AccountID, ad.city
        ) T1 ON T1.AccountID = A.AccountID
        INNER JOIN
        (
            SELECT 
                ad.AccountID,
                CASE WHEN COUNT(DISTINCT(ad.City)) > 1 THEN 'Multiple' ELSE MIN(ad.City) END AS City
            FROM Addresses ad   
            GROUP BY ad.AccountID
        ) T2
        ON T2.AccountID = A.AccountID
        WHERE 
            a.AccountID = 1
        

        【讨论】:

          【解决方案4】:

          这是另一个使用CROSS APPLY的解决方案

          SELECT
              AccountID
          ,   CASE 
                  WHEN x.countOfDistinctAddressLine = 1 AND x.countOfDistinctCity = 1
                  THEN x.firstAddressLine
                  ELSE 'Multiple'
                  END AS AddressLine
          ,   CASE 
                  WHEN x.countOfDistinctAddressLine = 1 AND x.countOfDistinctCity = 1
                  THEN x.firstCity
                  ELSE 'Multiple'
                  END AS City
          FROM
              Addresses AS source
          CROSS APPLY
              (
                  SELECT
                      COUNT(DISTINCT AddressLine) AS countOfDistinctAddressLine
                  ,   COUNT(DISTINCT City) AS countOfDistinctCity
                  ,   MIN(AddressLine) AS firstAddressLine
                  ,   MIN(City) AS firstCity
                  FROM
                      Addresses
                  WHERE
                      AccountID = source.AccountID
              ) x
          GROUP BY
              AccountID
          ,   x.countOfDistinctAddressLine
          ,   x.countOfDistinctCity
          ,   x.firstAddressLine
          ,   x.firstCity;
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-01-09
            • 1970-01-01
            • 2012-07-26
            • 1970-01-01
            • 2023-03-28
            • 2019-04-04
            • 2012-02-13
            相关资源
            最近更新 更多