简体   繁体   English

聚合中最大值的计数 select

[英]Count of the max value in an aggregate select

I want to count the number of the number of the maximum value of the minimum values in a particular field.我想计算特定字段中最小值的最大值的数量。

This select is broken if I were to uncomment the lines:如果我取消注释这些行,则此 select 已损坏:

select clientnumber
      ,count(distinct clientname) as NumberUnique
      ,max(clientname) as UniqueSample1
      -- ,sum(case clientname when min(clientname) then 1 else 0 end) as UniqueCount1
      ,min(clientname) as UniqueSample2
      -- ,sum(case clientname when min(clientname) then 1 else 0 end) as UniqueCount2
  FROM dbo.InvoicesSent dt
 group by clientnumber
 having count(distinct clientname) > 1

Background: We are reviewing records that have two different names on the invoices for the same clientnumber.背景:我们正在审查同一客户编号的发票上有两个不同名称的记录。 Knowing which one of the two has the higher count is handy for the analysis.知道两者中哪一个的计数更高有助于分析。

Note: I know there are other solutions that can take into account more than 2 unique values but at this point, I want to solve this problem for its academic value.注意:我知道还有其他解决方案可以考虑超过 2 个唯一值,但在这一点上,我想解决这个问题的学术价值。 I also know I could solve this with a subselect but I am holding out for some graceful solution.我也知道我可以通过子选择来解决这个问题,但我坚持要一些优雅的解决方案。

If you know that there are two names, then you could do this without a subselect:如果您知道有两个名称,那么您可以在没有子选择的情况下执行此操作:

select top (1) with ties clientnumber, 
       min(clientname) over (partition by clientnumber) as min_name,
       max(clientname) over (partition by clientnumber) as max_name,
       (case when clientname = min(clientname) over (partition by clientnumber)
             then count(*)
             else sum(count(*)) over (partition by clientnumber) - count(*)
        end) as min_count,
       (case when clientname = max(clientname) over (partition by clientnumber)
             then count(*)
             else sum(count(*)) over (partition by clientnumber) - count(*)
        end) as max_count
from InvoicesSent i
group by clientnumber, clientname
order by row_number() over (partition by clientnumber order by clientname) +
         (case when min(clientname) over (partition by clientnumber) = max(clientname) over (partition by clientnumber) then 1 else 0 end);

I am not arguing that this is elegant.我并不是说这很优雅。 Merely that it is possible for your conditions.只是根据您的条件是可能的。

Here is a slightly simpler form:这是一个稍微简单的形式:

select top (1) with ties clientnumber, 
       clientname as min_name,
       max(clientname) over (partition by clientnumber) as max_name,
       count(*) as min_count,
       sum(count(*)) over (partition by clientnumber) - count(*) max_count
from InvoicesSent i
group by clientnumber, clientname
order by row_number() over (partition by clientnumber order by clientname) +
         (case when count(*) over (partition by clientnumber) >= 2 then 0 else 1 end)

And a db<>fiddle .还有一个db<>fiddle

Actually, this isn't so bad.其实,这并没有那么糟糕。 It is aggregating by the name column and the client, putting all the data on one row using window functions and then selecting the one row.它按名称列和客户端聚合,使用 window 函数将所有数据放在一行上,然后选择一行。 There is a little trick in the order by to only select clients with more than one name.仅对具有多个名称order by有一个小技巧。

If you are making use of sql server that supports string_agg the following can be done如果您正在使用支持 string_agg 的 sql 服务器,则可以执行以下操作

Here is a db fiddble link https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=4184c994d37e0dc7178212cd657ba15f这是一个 db fiddle 链接https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=4184c994d37e0dc7178212cd657ba15f

create table invoices(id int identity, clientnumber int, clientname varchar(100));

insert into invoices(clientnumber,clientname)
select t.clientnumber,clientname
  from (values(100,'Adam')
             ,(100,'Adam')
             ,(100,'Abraham')
             ,(101,'Grace')
             ,(101,'Grace')
             ,(102,'Paul')
       )t(clientnumber,clientname);



select clientnumber
      ,string_agg(concat(clientname,'-',cnt),';') as clientname_and_cnt
 from(     
select distinct
       clientnumber
      ,clientname
      ,count(*) over(partition by clientnumber,clientname) as cnt
  from invoices
     )x
group by clientnumber     
order by 2 desc

Output
+--------------+--------------------+
| clientnumber | clientname_and_cnt |
+--------------+--------------------+
|          102 | Paul-1             |
|          101 | Grace-2            |
|          100 | Abraham-1;Adam-2   |
+--------------+--------------------+

And if you want to show up those which have two or more clientnames by clientnumber then Add the following in the having clause如果你想通过 clientnumber 显示那些有两个或多个客户名的,那么在 having 子句中添加以下内容

having(charindex(';',string_agg(concat(clientname,'-',cnt),';')))<>0

If you would like ordering based on the number of invoices by the clientname then you may also do the following (within group clause)如果您想根据客户名称的发票数量订购,那么您也可以执行以下操作(在组子句中)

select clientnumber
      ,string_agg(concat(clientname,'-',cnt),';') within group(order by cnt desc) as clientname_and_cnt
 from(     
select distinct
       clientnumber
      ,clientname
      ,count(*) over(partition by clientnumber,clientname) as cnt
  from invoices
     )x
group by clientnumber     
order by 2 desc

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM