在SUM字段

时间:2016-01-11 11:59:53

标签: sql-server sql-server-2008 where having

问题

我们有一个Users表和一个Addresses表。每个用户可以拥有多个地址。我们有一个名为 IsDefault 的字段,用户可以在其中选择默认地址。该字段目前不是强制性的,可能将来也是如此,因此我需要做一些分析。现在我想验证地址以查看:

  • 给定用户有多少个地址。
  • 这些地址中有多少(如果地址超过1个) IsDefault标志设置为1。

基本上我想知道有多少用户有多个地址没有打开他们的任何地址作为默认地址。

到目前为止,我有以下SQL查询:

SELECT  AD.User_Id,
        COUNT(AD.User_Id) AS HowManyAddresses,
        SUM(
            CASE WHEN 
                AD.IsDefault IS NULL 
                OR
                AD.IsDefault = 0
            THEN
                1
            ELSE
                0
            END
        ) AS DefaultEmpty,

        SUM(
            CASE WHEN 
                AD.IsDefault = 1
            THEN
                1
            ELSE
                0
            END
        ) AS DefaultAddress

FROM dbo.Addresses AS AD
    JOIN dbo.Users AS U
    ON U.Id = AD.User_Id
GROUP BY AD.User_ID
ORDER BY AD.User_Id

我发现的问题是我想检查DefaultAddressDefaultEmpty SELECT SUM字段中的值,但是在尝试使用WHERE或HAVING引用它们时出现以下错误:

  

无效的列名'DefaultEmpty'。

是否无法引用SUM值以供选择?

技术使用:

  1. SQL Server 2008
  2. SQL Server Management Studio 2008

4 个答案:

答案 0 :(得分:1)

实际上你需要用这样的SUM重复整个HAVING条款 -

SELECT
    AD.User_Id
    ,COUNT(AD.User_Id) AS HowManyAddresses
    ,SUM(
    CASE
        WHEN
            AD.IsDefault IS NULL OR
            AD.IsDefault = 0 THEN 1
        ELSE 0
    END
    ) AS DefaultEmpty
    ,SUM(
    CASE
        WHEN
            AD.IsDefault = 1 THEN 1
        ELSE 0
    END
    ) AS DefaultAddress

FROM dbo.Addresses AS AD
JOIN dbo.Users AS U
    ON U.Id = AD.User_Id
GROUP BY AD.User_ID
HAVING SUM(
CASE
    WHEN
        AD.IsDefault IS NULL OR
        AD.IsDefault = 0 THEN 1
    ELSE 0
END
) = 0
ORDER BY AD.User_Id

OR

DECLARE @address TABLE(UserID INT,Address VARCHAR(100),IsDefault BIT);
INSERT INTO @address VALUES
 (1,'User 1 default',1)
,(2,'User 2 non default',0)
,(3,'User 3 non default',0)
,(3,'User 3 default',1)
,(4,'User 4 default',1)
,(4,'User 4 second default',1);

SELECT
    COUNT(*) OVER () AS HowManyAddresses
    ,ISNULL(def0.DefaultEmpty, 0) AS DefaultEmpty
    ,ISNULL(def1.DefaultAddress, 0) AS DefaultAddress
FROM (SELECT
        AD.Address
        ,COUNT(AD.UserID) OVER (PARTITION BY AD.UserID) AS DefaultEmpty
    FROM @address AS AD
    WHERE (AD.IsDefault = 0)) def0
FULL JOIN (SELECT
        AD.Address
        ,COUNT(AD.UserID) OVER (PARTITION BY AD.UserID) AS DefaultAddress
    FROM @address AS AD
    WHERE (AD.IsDefault = 1)) def1
    ON def0.Address = def1.Address

答案 1 :(得分:1)

这将计算 - 按用户和默认分组,有多少个地址:

DECLARE @user TABLE(ID INT, Name VARCHAR(100));
INSERT INTO @user VALUES
 (1,'user1') --will get a default
,(2,'user2') --no default
,(3,'user3') --both
,(4,'user4') --two defaults
,(5,'user5');--nothing

DECLARE @address TABLE(UserID INT,Address VARCHAR(100),IsDefault BIT);
INSERT INTO @address VALUES
 (1,'User 1 default',1)
,(2,'User 2 non default',0)
,(3,'User 3 non default',0)
,(3,'User 3 default',1)
,(4,'User 4 default',1)
,(4,'User 4 second default',1);

编辑:PIVOT更好......

SELECT p.*
FROM
(
    SELECT u.ID,u.Name
          ,CASE WHEN a.IsDefault=1 THEN 'DEFAULT' ELSE 'NORMAL' END AS PivotColumn
          ,COUNT(a.UserID) AS CountPerUserAndDefault
    FROM @user AS u
    LEFT JOIN @address AS a ON u.ID=a.UserID
    GROUP BY u.ID,u.Name,a.IsDefault
) AS tbl
PIVOT
(
    SUM(CountPerUserAndDefault) FOR PivotColumn IN([DEFAULT],[NORMAL])
) AS p

结果:

Name    ID  DEFAULT NORMAL
user1   1   1       NULL
user2   2   NULL    1
user3   3   1       1
user4   4   2       NULL
user5   5   NULL    0

答案 2 :(得分:1)

如果要在CTE子句中使用别名,可以在下面使用WHERE

WITH cte AS (
SELECT  AD.User_Id,
        COUNT(AD.User_Id) AS HowManyAddresses,
        SUM(
            CASE WHEN 
                AD.IsDefault IS NULL 
                OR
                AD.IsDefault = 0
            THEN
                1
            ELSE
                0
            END
        ) AS DefaultEmpty,

        SUM(
            CASE WHEN 
                AD.IsDefault = 1
            THEN
                1
            ELSE
                0
            END
        ) AS DefaultAddress

FROM dbo.Addresses AS AD
    JOIN dbo.Users AS U
    ON U.Id = AD.User_Id
GROUP BY AD.User_ID
ORDER BY AD.User_Id
)
SELECT * 
FROM cte
WHERE /* You can use alias names here... */
GROUP BY /* You can use alias names here... */
HAVING /* You can use alias names here... */

答案 3 :(得分:0)

将其放在GROUPBY之后:

HAVING SUM(CAST(AD.IsDefault AS INT)) > 0