SQL: True/False/Null 位域的 SUM

SQL: True/False/Null SUM of a Bit field

我在 MS-SQL Server 2005 上有以下 table。

CREATE TABLE tblData(ID INT NOT NULL PRIMARY KEY,
                     FOOBAR1 BIT,
                     LOCATION VARCHAR(50));

INSERT INTO tblData (ID, FOOBAR1, LOCATION) 
VALUES (1,'True','Paris'), (2,'True','New York'), (3,'False','Paris')
     , (4,'False',NULL), (5,NULL,'Paris');

tblCities 看起来像这样:

CREATE TABLE tblCities(cityName VARCHAR(50));
INSERT INTO tblCities (cityName) 
VALUES ('Paris'), ('New York'), ('London');

我想要 FOOBAR1 位的聚合(True、False 和 NULL)所以这是我试过的 SELECT 语句:

SELECT
    UPPER(tblCities.cityName) AS City
    ,SUM (CASE WHEN tblData.FOOBAR1 = 1 THEN 1 ELSE 0 END) AS Yes
    ,SUM (CASE WHEN tblData.FOOBAR1 = 0 THEN 1 ELSE 0 END) AS [No]
    ,SUM (CASE WHEN tblData.FOOBAR1 IS NULL THEN 1 ELSE 0 END) AS NoData
FROM tblCities 
LEFT JOIN tblData ON tblCities.cityName = tblData.LOCATION
GROUP BY tblCities.cityName

结果如下:

City     | Yes | No | NoData |
LONDON   | 0   | 0  | 1      |
NEW YORK | 1   | 0  | 0      |
PARIS    | 1   | 1  | 1      |

理想情况下,我希望 tblData 中的所有五个记录都包含在 SELECT 语句中:

City     | Yes | No | NoData |
LONDON   | 0   | 0  | 0      |
NEW YORK | 1   | 0  | 0      |
PARIS    | 1   | 1  | 1      |
NO DATA  | 0   | 1  | 0      |
SELECT isnull(UPPER(tblData.LOCATION),'NO CITY')
      ,SUM (CASE WHEN tblData.FOOBAR1 = 1     THEN 1 ELSE 0 END) AS Yes
      ,SUM (CASE WHEN tblData.FOOBAR1 = 0     THEN 1 ELSE 0 END) AS [No]
      ,SUM (CASE WHEN tblData.FOOBAR1 IS NULL THEN 1 ELSE 0 END) AS NoData
FROM tblData 
GROUP BY isnull(tblData.LOCATION,'NO CITY')  

SELECT isnull(tblCities.cityName, isnull(tblData.LOCATION,'No City'))
      ,SUM (CASE WHEN tblData.FOOBAR1 = 1     THEN 1 ELSE 0 END) AS Yes
      ,SUM (CASE WHEN tblData.FOOBAR1 = 0     THEN 1 ELSE 0 END) AS [No]
      ,SUM (CASE WHEN tblData.FOOBAR1 IS NULL THEN 1 ELSE 0 END) AS NoData
FROM          tblCities 
FULL OUT JOIN tblData 
               ON tblCities.cityName = tblData.LOCATION
GROUP BY isnull(tblCities.cityName, isnull(tblData.LOCATION,'No City'))

来自评论:

example: INSERT INTO tblCities (cityName) VALUES ('Vancouver') ), that city will also have ' 1 ' in the NoData column in tblData.

如果你想处理 NO DATA 你必须改变条件:

SELECT
     [City]   = ISNULL(UPPER(tc.cityName), 'NO DATA')
    ,[Yes]    = SUM(CASE WHEN td.FOOBAR1 = 1 THEN 1 ELSE 0 END)
    ,[No]     = SUM(CASE WHEN td.FOOBAR1 = 0 THEN 1 ELSE 0 END)
    ,[NoData] = SUM(CASE WHEN td.FOOBAR1 IS NULL 
                         AND td.LOCATION IS NOT NULL THEN 1 ELSE 0 END)
FROM tblCities  tc
FULL JOIN tblData td
  ON tc.cityName = td.LOCATION
GROUP BY tc.cityName;

LiveDemo

输出:

╔═══════════╦═════╦════╦════════╗
║   City    ║ Yes ║ No ║ NoData ║
╠═══════════╬═════╬════╬════════╣
║ NO DATA   ║   0 ║  1 ║      0 ║
║ LONDON    ║   0 ║  0 ║      0 ║
║ NEW YORK  ║   1 ║  0 ║      0 ║
║ PARIS     ║   1 ║  1 ║      1 ║
║ VANCOUVER ║   0 ║  0 ║      0 ║
╚═══════════╩═════╩════╩════════╝

警告:

您应该为您的 tblCities table 添加人工密钥并使用它加入。将 CityName 存储在两个 table 中并不是最好的主意。