SQL Server count() over() 与 distinct
SQLServer count() over() with distinct
我正在做一个项目,我们需要计算不同行的数量。该场景的简化版本包括 user
table、keyword
table 和 keyword_user
table.
user
table 仅包含常见的用户元数据,如姓名等。其他 table 如下所列。
keyword_user:
id
user_id
keyword_id
关键词:
id,
description
我想做的是根据用户 keyword_id 找到最大用户数 (5),同时计算匹配行的总数。计数必须不同。
查询:
SELECT TOP 5 u.[id],
u.[firstname],
u.[lastname],
total = Count(*) OVER()
FROM [user] u
INNER JOIN [keyword_user] ku
ON u.[id] = ku.[user_id]
WHERE ( ku.keyword_id IN ( '5f6501ec-0a71-4067-a21d-3c5f87a76411', 'c19b95c0-8554-4bbd-9526-db8f1c4f1edf'))
AND u.id NOT IN ( '12db3001-b3b9-4626-8a02-2519102cb53a' )
结果集:
+--------------------------------------+-----------+----------+-------+
| id | firstname | lastname | total |
+--------------------------------------+-----------+----------+-------+
| F0527AC3-747A-45A6-9CF9-B1F6C7F548F8 | Kasper | Thomsen | 3 |
| 95988F6D-9C91-4779-B6C3-3D4B4D6AE836 | Michael | Jacobsen | 3 |
| 95988F6D-9C91-4779-B6C3-3D4B4D6AE836 | Michael | Jacobsen | 3 |
+--------------------------------------+-----------+----------+-------+
问题:
这里的问题是,Michael 被计算了两次,因此总计数是 3,而我希望它是 2。使用 count() over()
时,您无法将包含不同的表达式解析到其中.另外,如果我只是 SELECT DISTINCT
,我的结果集看起来不错,除了总计数,它仍然是 3。
如果我需要包含更多信息来支持这个问题,请告诉我,我会尽力回答。
MSSQL 创建数据库脚本(示例数据)
想要的结果集:
+--------------------------------------+-----------+----------+-------+
| id | firstname | lastname | total |
+--------------------------------------+-----------+----------+-------+
| F0527AC3-747A-45A6-9CF9-B1F6C7F548F8 | Kasper | Thomsen | 2 |
| 95988F6D-9C91-4779-B6C3-3D4B4D6AE836 | Michael | Jacobsen | 2 |
+--------------------------------------+-----------+----------+-------+
试试这个:
我创建了两个临时 tables(#user
和 #user_key
)并填充它们。
create table #user (id int, name varchar(20))
create table #user_key (id int, fk_user int, content varchar(50))
insert into #user values
(1, 'Giuseppe'),
(2, 'Anna'),
(3, 'Angela'),
(4, 'Maria'),
(5, 'Ethra'),
(6, 'Piero')
insert into #user_key values
(1, 1, 'ciao'),
(2, 1, 'hello'),
(3, 2, 'hallo'),
(4, 4, 'hullo')
提取查询:
我使用 main table #user
,所以我添加了一个关于总计数的子查询,但在 order by 子句中,我尝试为用户排序他们的关键字。您可以添加其他条件(如您的 In / NOT IN)
select top 5 id, name, (select COUNT(*) from #user_key uk)
from #user u
order by (select COUNT(*) from #user_key uk where uk.fk_user = u.id) desc
编辑
你想要这个吗?:
97D476C2-B52C-4D44-A460-44472CBF8817 Michael testing 2
F4FE5550-BC69-437E-91A0-5B11E0D9279E Kasper Test 2
还是这个?
97D476C2-B52C-4D44-A460-44472CBF8817 Michael testing 2
F4FE5550-BC69-437E-91A0-5B11E0D9279E Kasper Test 2
12DB3001-B3B9-4626-8A02-2519102CB53A Thomas Teil 2
你可以试试:
SELECT TOP 5 * FROM (
SELECT
u.[id],
u.[firstname],
u.[lastname],
total = Count(*) OVER(PARTITION BY ku.keyword_id),
rownum = ROW_NUMBER() OVER(PARTITION BY ku.keyword_id ORDER BY u.ID)
FROM [user] u
INNER JOIN [keyword_user] ku
ON u.[id] = ku.[user_id]
WHERE (ku.keyword_id IN ( '5f6501ec-0a71-4067-a21d-3c5f87a76411', 'c19b95c0-8554-4bbd-9526-db8f1c4f1edf'))
AND u.id NOT IN ( '12db3001-b3b9-4626-8a02-2519102cb53a' )
) AS A ORDER BY A.rownum DESC
我对你的情况有点困惑,特别是 "keywords" 以及它们与每个用户的关系(这对我来说只是一个过程问题)因此发现自己通过包含你的初始查询作为我的来源 table.
请在下方发表评论,以便我们改进。
SELECT
id
, firstname
, lastname
, total
, COUNT(*) AS [per_user_count]
FROM (
SELECT TOP 5 u.[id],
u.[firstname],
u.[lastname],
total = Count(*) OVER()
FROM [user] u
INNER JOIN [keyword_user] ku
ON u.[id] = ku.[user_id]
WHERE
(
ku.keyword_id IN (
'5f6501ec-0a71-4067-a21d-3c5f87a76411'
, 'c19b95c0-8554-4bbd-9526-db8f1c4f1edf'
)
)
AND u.id NOT IN ('12db3001-b3b9-4626-8a02-2519102cb53a')
) AS T
GROUP BY
T.id
, T.firstname
, T.lastname
, T.total
编辑:我们在那里真的很困惑,所以我创建了一个更简单的脚本,它应该排除关键字,只排除唯一用户(以生成总体总数)并获得其中的前 5 个(随机顺序)。
SELECT
TOP 5
T.id
, T.firstname
, T.lastname
, Total = COUNT(*) OVER()
FROM (
SELECT DISTINCT
u.*
FROM [keyword_user] ku
LEFT JOIN [user] u
ON
ku.user_id = u.id
WHERE
(
ku.keyword_id IN (
'5f6501ec-0a71-4067-a21d-3c5f87a76411'
, 'c19b95c0-8554-4bbd-9526-db8f1c4f1edf')
)
AND ku.[user_id] NOT IN (
'12db3001-b3b9-4626-8a02-2519102cb53a'
)
) AS T
谢谢
编辑:您的方案是直接 "search of keywords" 链接到一个实体,具有总计数和前 5 名结果。正如我对 CTE 的理解(基于 MSDN),CTE 是分层数据挖掘的一个很好的解决方案(不需要做 while 和做任何后空翻来获得你的组织层次结构)这并不适合我们这里的场景。
你真的应该在问题中解释你需要什么,而不是在评论中。
在 CTE_Users
中,我们找到给定关键字的所有不同用户。
然后将结果与 user
连接起来以获取用户详细信息。至少它会产生您使用给定的小样本数据所期望的结果。
WITH
CTE_Users
AS
(
SELECT DISTINCT ku.user_id
FROM
keyword_user AS ku
WHERE
ku.keyword_id IN (
'5f6501ec-0a71-4067-a21d-3c5f87a76411',
'c19b95c0-8554-4bbd-9526-db8f1c4f1edf')
AND ku.user_id NOT IN (
'12db3001-b3b9-4626-8a02-2519102cb53a')
)
SELECT TOP(5)
u.id
,u.firstname
,u.lastname
,COUNT(*) OVER() AS total
FROM
user AS u
INNER JOIN CTE_Users ON CTE_Users.user_id = u.id
;
我正在做一个项目,我们需要计算不同行的数量。该场景的简化版本包括 user
table、keyword
table 和 keyword_user
table.
user
table 仅包含常见的用户元数据,如姓名等。其他 table 如下所列。
keyword_user:
id
user_id
keyword_id
关键词:
id,
description
我想做的是根据用户 keyword_id 找到最大用户数 (5),同时计算匹配行的总数。计数必须不同。
查询:
SELECT TOP 5 u.[id],
u.[firstname],
u.[lastname],
total = Count(*) OVER()
FROM [user] u
INNER JOIN [keyword_user] ku
ON u.[id] = ku.[user_id]
WHERE ( ku.keyword_id IN ( '5f6501ec-0a71-4067-a21d-3c5f87a76411', 'c19b95c0-8554-4bbd-9526-db8f1c4f1edf'))
AND u.id NOT IN ( '12db3001-b3b9-4626-8a02-2519102cb53a' )
结果集:
+--------------------------------------+-----------+----------+-------+
| id | firstname | lastname | total |
+--------------------------------------+-----------+----------+-------+
| F0527AC3-747A-45A6-9CF9-B1F6C7F548F8 | Kasper | Thomsen | 3 |
| 95988F6D-9C91-4779-B6C3-3D4B4D6AE836 | Michael | Jacobsen | 3 |
| 95988F6D-9C91-4779-B6C3-3D4B4D6AE836 | Michael | Jacobsen | 3 |
+--------------------------------------+-----------+----------+-------+
问题:
这里的问题是,Michael 被计算了两次,因此总计数是 3,而我希望它是 2。使用 count() over()
时,您无法将包含不同的表达式解析到其中.另外,如果我只是 SELECT DISTINCT
,我的结果集看起来不错,除了总计数,它仍然是 3。
如果我需要包含更多信息来支持这个问题,请告诉我,我会尽力回答。
MSSQL 创建数据库脚本(示例数据)
想要的结果集:
+--------------------------------------+-----------+----------+-------+
| id | firstname | lastname | total |
+--------------------------------------+-----------+----------+-------+
| F0527AC3-747A-45A6-9CF9-B1F6C7F548F8 | Kasper | Thomsen | 2 |
| 95988F6D-9C91-4779-B6C3-3D4B4D6AE836 | Michael | Jacobsen | 2 |
+--------------------------------------+-----------+----------+-------+
试试这个:
我创建了两个临时 tables(#user
和 #user_key
)并填充它们。
create table #user (id int, name varchar(20))
create table #user_key (id int, fk_user int, content varchar(50))
insert into #user values
(1, 'Giuseppe'),
(2, 'Anna'),
(3, 'Angela'),
(4, 'Maria'),
(5, 'Ethra'),
(6, 'Piero')
insert into #user_key values
(1, 1, 'ciao'),
(2, 1, 'hello'),
(3, 2, 'hallo'),
(4, 4, 'hullo')
提取查询:
我使用 main table #user
,所以我添加了一个关于总计数的子查询,但在 order by 子句中,我尝试为用户排序他们的关键字。您可以添加其他条件(如您的 In / NOT IN)
select top 5 id, name, (select COUNT(*) from #user_key uk)
from #user u
order by (select COUNT(*) from #user_key uk where uk.fk_user = u.id) desc
编辑
你想要这个吗?:
97D476C2-B52C-4D44-A460-44472CBF8817 Michael testing 2
F4FE5550-BC69-437E-91A0-5B11E0D9279E Kasper Test 2
还是这个?
97D476C2-B52C-4D44-A460-44472CBF8817 Michael testing 2
F4FE5550-BC69-437E-91A0-5B11E0D9279E Kasper Test 2
12DB3001-B3B9-4626-8A02-2519102CB53A Thomas Teil 2
你可以试试:
SELECT TOP 5 * FROM (
SELECT
u.[id],
u.[firstname],
u.[lastname],
total = Count(*) OVER(PARTITION BY ku.keyword_id),
rownum = ROW_NUMBER() OVER(PARTITION BY ku.keyword_id ORDER BY u.ID)
FROM [user] u
INNER JOIN [keyword_user] ku
ON u.[id] = ku.[user_id]
WHERE (ku.keyword_id IN ( '5f6501ec-0a71-4067-a21d-3c5f87a76411', 'c19b95c0-8554-4bbd-9526-db8f1c4f1edf'))
AND u.id NOT IN ( '12db3001-b3b9-4626-8a02-2519102cb53a' )
) AS A ORDER BY A.rownum DESC
我对你的情况有点困惑,特别是 "keywords" 以及它们与每个用户的关系(这对我来说只是一个过程问题)因此发现自己通过包含你的初始查询作为我的来源 table.
请在下方发表评论,以便我们改进。
SELECT
id
, firstname
, lastname
, total
, COUNT(*) AS [per_user_count]
FROM (
SELECT TOP 5 u.[id],
u.[firstname],
u.[lastname],
total = Count(*) OVER()
FROM [user] u
INNER JOIN [keyword_user] ku
ON u.[id] = ku.[user_id]
WHERE
(
ku.keyword_id IN (
'5f6501ec-0a71-4067-a21d-3c5f87a76411'
, 'c19b95c0-8554-4bbd-9526-db8f1c4f1edf'
)
)
AND u.id NOT IN ('12db3001-b3b9-4626-8a02-2519102cb53a')
) AS T
GROUP BY
T.id
, T.firstname
, T.lastname
, T.total
编辑:我们在那里真的很困惑,所以我创建了一个更简单的脚本,它应该排除关键字,只排除唯一用户(以生成总体总数)并获得其中的前 5 个(随机顺序)。
SELECT
TOP 5
T.id
, T.firstname
, T.lastname
, Total = COUNT(*) OVER()
FROM (
SELECT DISTINCT
u.*
FROM [keyword_user] ku
LEFT JOIN [user] u
ON
ku.user_id = u.id
WHERE
(
ku.keyword_id IN (
'5f6501ec-0a71-4067-a21d-3c5f87a76411'
, 'c19b95c0-8554-4bbd-9526-db8f1c4f1edf')
)
AND ku.[user_id] NOT IN (
'12db3001-b3b9-4626-8a02-2519102cb53a'
)
) AS T
谢谢
编辑:您的方案是直接 "search of keywords" 链接到一个实体,具有总计数和前 5 名结果。正如我对 CTE 的理解(基于 MSDN),CTE 是分层数据挖掘的一个很好的解决方案(不需要做 while 和做任何后空翻来获得你的组织层次结构)这并不适合我们这里的场景。
你真的应该在问题中解释你需要什么,而不是在评论中。
在 CTE_Users
中,我们找到给定关键字的所有不同用户。
然后将结果与 user
连接起来以获取用户详细信息。至少它会产生您使用给定的小样本数据所期望的结果。
WITH
CTE_Users
AS
(
SELECT DISTINCT ku.user_id
FROM
keyword_user AS ku
WHERE
ku.keyword_id IN (
'5f6501ec-0a71-4067-a21d-3c5f87a76411',
'c19b95c0-8554-4bbd-9526-db8f1c4f1edf')
AND ku.user_id NOT IN (
'12db3001-b3b9-4626-8a02-2519102cb53a')
)
SELECT TOP(5)
u.id
,u.firstname
,u.lastname
,COUNT(*) OVER() AS total
FROM
user AS u
INNER JOIN CTE_Users ON CTE_Users.user_id = u.id
;