如何 Select 每个类别的前 n 条记录
How to Select top n Records for Each Category
我正在尝试编写一个连接 2 个表的查询,它将为我提供前 5 个名称以及他们在特定日期范围(即 01-01-2016 到 12-31 之间的某个位置)销售的商品数量-2017.
根据我一直在研究的内容,这就是我想出的:
SELECT
EmployeeName,
COUNT(ID) AS 'Number of Deals',
CompanyNumber
FROM
(
SELECT
EmployeeName,
DealID,
CompanyNumber,
ROW_NUMBER() OVER (PARTITION BY CompanyNumber ORDER BY DealID) AS rn
FROM Deal
JOIN DealEmployee
ON Deal.DealID. =DealEmployee.DealID AS T
WHERE
Deal.Status = 2 AND
Date BETWEEN '2016-01-01' AND '2017-12-31' AND
EmployeeName != '' AND T.rn <=5
我希望得到以下结果:
我是新手,我知道我的语法不正确。提供任何帮助将不胜感激
在calculated/materialized之后,您需要在子查询之外的行号上进行过滤。我想这就是你想要的:
SELECT EmployeeName, CompanyNumber, cnt
FROM
(
SELECT EmployeeName, CompanyNumber, COUNT(*) AS cnt,
ROW_NUMBER() OVER (PARTITION BY CompanyNumber ORDER BY COUNT(*) DESC) rn
FROM Deal d
INNER JOIN DealEmployee de
ON d.DealID = de.DealID
WHERE d.Status = 2 AND Date BETWEEN '2016-01-01' AND '2017-12-31' AND
EmployeeName != ''
GROUP BY EmployeeName, CompanyNumber
) t
WHERE rn <= 5
ORDER BY
CompanyNumber,
cnt DESC;
请注意,我们在子查询内执行 GROUP BY
聚合,我们还计算行号。
未测试,但我会尝试类似的方法:
with
basedata as (
select EmployeeName
, CompanyNumber
, COUNT(ID) as Number_of_Deals
from Deal
join DealEmployee
on Deal.DealID = DealEmployee.DealID
where Deal.Status = 2
and Date between '2016-01-01' and '2017-12-31'
and EmployeeName !=''
group by EmployeeName
, CompanyNumber
)
,
basedata_with_rank as (
select t.*
, row_number() over (partition by CompanyNumber order by Number_of_Deals desc) rn
from basedata
)
select *
from basedata_with_rank
where rn <= 5
order by CompanyNumber
, Number_of_Deals desc
使用 CTE 通常可以提高查询的可读性。顺便说一句:我会避免给列命名 "date"(一个保留字),并且我会始终为我的列使用限定名称。也许使用解析函数 rank 或 dense rank 会更合适,但 row_number 也应该有效。
我想你想要这个:
SELECT EmployeeName, num_deals, CompanyNumber
FROM (SELECT EmployeeName, CompanyNumber, COUNT(*) as num_deals,
ROW_NUMBER() OVER (PARTITION BY CompanyNumber ORDER BY COUNT(*) DESC) AS seqnum
FROM Deal d JOIN
DealEmployee de
ON Deal.DealID. = de.DealID
WHERE d.Status = 2 AND
Date BETWEEN '2016-01-01' AND '2017-12-31' AND
EmployeeName <> ''
GROUP BY employee, CompanyNumber
) t
WHERE seqnum <= 5;
备注:
- 您需要在执行
row_number()
之前进行聚合,因为您要根据计数进行枚举。 (此版本将聚合和 row_number()
合并到一个子查询中;聚合在前。)
- 交易数量按员工和公司汇总。
- 当您有多个 table 时,限定 所有 列名称。
- 您的查询还有许多其他错误,例如 table 别名放错位置以及缺少某些行。
我正在尝试编写一个连接 2 个表的查询,它将为我提供前 5 个名称以及他们在特定日期范围(即 01-01-2016 到 12-31 之间的某个位置)销售的商品数量-2017.
根据我一直在研究的内容,这就是我想出的:
SELECT
EmployeeName,
COUNT(ID) AS 'Number of Deals',
CompanyNumber
FROM
(
SELECT
EmployeeName,
DealID,
CompanyNumber,
ROW_NUMBER() OVER (PARTITION BY CompanyNumber ORDER BY DealID) AS rn
FROM Deal
JOIN DealEmployee
ON Deal.DealID. =DealEmployee.DealID AS T
WHERE
Deal.Status = 2 AND
Date BETWEEN '2016-01-01' AND '2017-12-31' AND
EmployeeName != '' AND T.rn <=5
我希望得到以下结果:
我是新手,我知道我的语法不正确。提供任何帮助将不胜感激
在calculated/materialized之后,您需要在子查询之外的行号上进行过滤。我想这就是你想要的:
SELECT EmployeeName, CompanyNumber, cnt
FROM
(
SELECT EmployeeName, CompanyNumber, COUNT(*) AS cnt,
ROW_NUMBER() OVER (PARTITION BY CompanyNumber ORDER BY COUNT(*) DESC) rn
FROM Deal d
INNER JOIN DealEmployee de
ON d.DealID = de.DealID
WHERE d.Status = 2 AND Date BETWEEN '2016-01-01' AND '2017-12-31' AND
EmployeeName != ''
GROUP BY EmployeeName, CompanyNumber
) t
WHERE rn <= 5
ORDER BY
CompanyNumber,
cnt DESC;
请注意,我们在子查询内执行 GROUP BY
聚合,我们还计算行号。
未测试,但我会尝试类似的方法:
with
basedata as (
select EmployeeName
, CompanyNumber
, COUNT(ID) as Number_of_Deals
from Deal
join DealEmployee
on Deal.DealID = DealEmployee.DealID
where Deal.Status = 2
and Date between '2016-01-01' and '2017-12-31'
and EmployeeName !=''
group by EmployeeName
, CompanyNumber
)
,
basedata_with_rank as (
select t.*
, row_number() over (partition by CompanyNumber order by Number_of_Deals desc) rn
from basedata
)
select *
from basedata_with_rank
where rn <= 5
order by CompanyNumber
, Number_of_Deals desc
使用 CTE 通常可以提高查询的可读性。顺便说一句:我会避免给列命名 "date"(一个保留字),并且我会始终为我的列使用限定名称。也许使用解析函数 rank 或 dense rank 会更合适,但 row_number 也应该有效。
我想你想要这个:
SELECT EmployeeName, num_deals, CompanyNumber
FROM (SELECT EmployeeName, CompanyNumber, COUNT(*) as num_deals,
ROW_NUMBER() OVER (PARTITION BY CompanyNumber ORDER BY COUNT(*) DESC) AS seqnum
FROM Deal d JOIN
DealEmployee de
ON Deal.DealID. = de.DealID
WHERE d.Status = 2 AND
Date BETWEEN '2016-01-01' AND '2017-12-31' AND
EmployeeName <> ''
GROUP BY employee, CompanyNumber
) t
WHERE seqnum <= 5;
备注:
- 您需要在执行
row_number()
之前进行聚合,因为您要根据计数进行枚举。 (此版本将聚合和row_number()
合并到一个子查询中;聚合在前。) - 交易数量按员工和公司汇总。
- 当您有多个 table 时,限定 所有 列名称。
- 您的查询还有许多其他错误,例如 table 别名放错位置以及缺少某些行。