Sql server TSQL分组并从子查询中选择行数
我有下表Sql server TSQL分组并从子查询中选择行数,sql-server,tsql,sql-server-2012,sql-server-2017,Sql Server,Tsql,Sql Server 2012,Sql Server 2017,我有下表 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 St
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值,否则返回“多个”。如果帐户具有相同的
城市
,则应选择该城市值,否则返回“多个”
例如,对于帐户ID 1,查询应该返回
AccountID AddressLine City
1 Multiple New York
这是
下面是我的问题(不起作用)。我认为问题在于分组和从子队列中选择计数
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
我想这应该可以。我使用该函数按汇总组中的地址,因为您只想在有单个值的情况下显示该值。我省略了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
下面是另一个使用交叉应用的解决方案
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;
下面是一个可以在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;
AccountID1返回
+-----------+-------------+----------+
| AccountID | AddressLine | City |
+-----------+-------------+----------+
| 1 | Multiple | New York |
+-----------+-------------+----------+
AccountID2返回
+-----------+----------------+---------------+
| AccountID | AddressLine | City |
+-----------+----------------+---------------+
| 2 | Lombard Street | San Francisco |
+-----------+----------------+---------------+
当然,这并没有考虑到多个城市价值观的可能性。不妨将我的价值观加入其中。它并不比其他任何东西都好,但不管怎样,它就在这里
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