在 SUM 字段上使用 HAVING 或 WHERE
Using HAVING or WHERE on SUM Fields
问题
我们有一个用户 table 和一个地址 table.Each 用户可以有多个地址。我们有一个名为 IsDefault
的位字段,用户可以在其中 select 他们的默认地址。这个字段目前不是强制性的,将来可能会是,所以我需要做一些分析。现在我想验证地址以查看:
- 给定用户有多少个地址。
- 这些地址中有多少(如果它们有超过 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
我发现的问题是我想检查 DefaultAddress
和 DefaultEmpty
SELECT SUM 字段中的值,但是在尝试引用它们时出现以下错误哪里或拥有:
Invalid column name 'DefaultEmpty'.
是否无法为 selection 目的引用 SUM 值?
使用的技术:
- SQL 服务器 2008
- SQL 服务器管理工作室 2008
实际上你需要像这样用 HAVING
重复整个 SUM
子句 -
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
或
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
这将计数 - 按用户和默认分组,有多少个地址:
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
如果要在 WHERE
子句中使用别名,可以在下面使用 CTE
:
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... */
把这个放在GROUPBY
之后:
HAVING SUM(CAST(AD.IsDefault AS INT)) > 0
问题
我们有一个用户 table 和一个地址 table.Each 用户可以有多个地址。我们有一个名为 IsDefault
的位字段,用户可以在其中 select 他们的默认地址。这个字段目前不是强制性的,将来可能会是,所以我需要做一些分析。现在我想验证地址以查看:
- 给定用户有多少个地址。
- 这些地址中有多少(如果它们有超过 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
我发现的问题是我想检查 DefaultAddress
和 DefaultEmpty
SELECT SUM 字段中的值,但是在尝试引用它们时出现以下错误哪里或拥有:
Invalid column name 'DefaultEmpty'.
是否无法为 selection 目的引用 SUM 值?
使用的技术:
- SQL 服务器 2008
- SQL 服务器管理工作室 2008
实际上你需要像这样用 HAVING
重复整个 SUM
子句 -
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
或
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
这将计数 - 按用户和默认分组,有多少个地址:
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
如果要在 WHERE
子句中使用别名,可以在下面使用 CTE
:
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... */
把这个放在GROUPBY
之后:
HAVING SUM(CAST(AD.IsDefault AS INT)) > 0