分组后分组合计以及总计SQL语句(稍微整理了一下)

今天看到了这个文章感觉内容挺多的,就是比较乱,实在不好整理,小编就简单整理了一下,希望大家能凑合看吧

分组后分组合计以及总计SQL语句
 
1)想一次性得到分组合计以及总计,sql:

SELECT 分组字段 FROM 表
GROUP BY 分组字段
compute sum(COUNT(*))

2)分组合计1:

SELECT COUNT(*)
FROM (SELECT 分组字段 FROM 表
GROUP BY 分组字段
)别名

 
3)分组合计2:

SELECT COUNT(*)
FROM (SELECT distinct 分组字段 FROM 表)别名

4)统计分组后的种类数:
 
例子1:分组合计

SELECT JSSKQK_JGH FROM SJ_JSSKQK WHERE JSSKQK_JGH IN (SELECT JSJBXX_JGH FROM SJ_JSJBXX WHERE JSJBXX_JSLXM1=1) GROUP BY JSSKQK_JGH HAVING ((SUM(JSSKQK_SSKCXS1) /40)>5)

上面的语句已经可以满足要求分组了.假设执行后有3条记录,怎么才能把这个COUNT值求出?

select count(*) from
(
SELECT JSSKQK_JGH
FROM SJ_JSSKQK
WHERE JSSKQK_JGH IN (SELECT JSJBXX_JGH FROM SJ_JSJBXX WHERE JSJBXX_JSLXM1=1)
GROUP BY JSSKQK_JGH HAVING ((SUM(JSSKQK_SSKCXS1) /40)>5)
) t

例子2:[PL/SQL] 如何得到分组后,组中最大日期的纪录

TABLE:A
A        B                C        D
1        2001/01/01                        1        1
1        2001/12/12                        2        2
3        2002/01/01                        3        3
3        2003/12/12                        4        4

按列A分组,请问如何得到每组中时间最大的数据?

1        2001/12/12                        2        2
3        2003/12/12                        4        4

我的笨方法:

SELECT *
FROM A
WHERE (A,B) IN(
SELECT A,MAX(B)
FROM A
GROUP BY A
)

有更好的方法吗?

1,select * from a out
where b = (select max(b) from a in
                         where in.a = out.a)

2,Select * from
(select a, row_number() over (partition by a
order by b desc) rn
from a)
where rn=1

3,Select a, b,c,d from
(select a, b,c,d,row_number() over (partition by a
order by b desc) rn
from a)
where rn=1

4,select A,B,C,D from test

  where rowid in
  (
     select rd from
     (
     select rowid rd ,rank() over(partion A order by B desc)rk from test
     ) where rk=1
    
    
  )
  )

例子3:SQL语句分组获取记录的第一条数据的方法
使用Northwind 数据库

首先查询Employees表

查询结果:

city列里面只有5个城市

使用ROW_NUMBER() OVER(PARTITION BY COL1 ORDER BY COL2) 先进行分组 注:根据COL1分组,在分组内部根据 COL2排序,而此函数计算的值就表示每组内部排序后的顺序编号(组内连续的唯一的).

sql语句为:

select EmployeeID,LastName,FirstName,Title,TitleOfCourtesy,City,ROW_NUMBER() over(partition by City order by EmployeeID) as new_index
from Employees

执行结果图:

可以看到是按照City分组,EmployeeID排序。

select出分组中的第一条记录

执行语句:

select * from
(select EmployeeID,LastName,FirstName,Title,TitleOfCourtesy,City,ROW_NUMBER() over(partition by City order by EmployeeID) as new_index
from Employees) a where a.new_index=1

执行结果图:

例子4:sql 获取分组结果后,如何每一组的第一条记录
Eric   red   20
eric   blue  30
andy red   10
andy  blue  5

例如,只获取黑体的记录。

1,declare @fTable table (fName varchar(10), fColor varchar(10), fOrder int)
 
insert into @fTable values(‘Eric’, ‘red’, 20)
insert into @fTable values(‘eric’, ‘blue’, 30)
insert into @fTable values(‘andy’, ‘red’, 10)
insert into @fTable values(‘andy’, ‘blue’, 5)
 
— 只获取红色
select * from @fTable where fColor = ‘red’
— 每个 fColor 取一条记录(按 fOrder 正序)
select * from @fTable A where fName = (select top 1 fName from @fTable where fColor = A.fColor order by fOrder )
— 每个 fColor 取一条记录(按 fOrder 反序)
select * from @fTable A where fName = (select top 1 fName from @fTable where fColor = A.fColor order by fOrder desc)
 
2,SQL2005以上版本
select * from (select *,row=row_number()over(partition by Color order by Color) from table1)t where row=1 and color=’xx’–加上條件

SQL2000用 top 1

例子5:一条SQL语句搞定分组并且每组限定记录集的数量
 
如果我想得到这样一个结果集:分组,并且每组限定记录集的数量,用一条SQL语句能办到吗?

比如说,我想找出学生期末考试中,每科的前3名,只用一条SQL语句,该怎么写?

表[TScore]的结构

code      学号 char
subject  科目 int
score     成绩 int

可以这样写:

    SELECT [code]
        ,[subject]
        ,[score]
    FROM (
        SELECT *
        ,RANK() OVER(PARTITION BY subject ORDER BY score DESC) AS Row
        FROM TScore
    ) AS a
    WHERE Row <= 3 ;

例子6:SQL获取每个分组的第一条记录

SQL查询以下伪数据获取粗体字行的记录
ID,Name,ItemID,Price,CreatedOn
1 a 1 10.00 1
2 a 1 12.00 2
3 b 1 9.00 1
4 b 1 11.50 2
5 c 1 20.00 1
6 a 2 21.00 1
7 a 2 23.00 2
8 b 2 35.00 1
9 c 2 31.00 1
10 c 2 30.50 2
 
获取每个分组中的第一条记录,当ItemID有多条记录时,选取Price最高的
 
–sql2000
select *
from tbname k
where not exists(select * from tbname where
 name=k.name and ITemID=K.ITemID and k.price<price
)
–sql2005
select ID,Name,ItemID,Price,CreatedOnfrom (select *,rn=ROW_NUMBER()over(PARTITION by name,ITemID order by price desc) from tb ) kwhere k.rn=1

例子7:分组后取第一条记录的SQL语句
分享

有如下表结构:  
  字段      A,       B,       C  
  值为      a1,     b1,     c1  
            a2,     b2,     c2  
            a2,     b3,     c3  
            a3,     b4,     c4  
            a3,     b5,     c5  

想要得到的结果集以A字段为分组条件,并取出每一个分组中的第一条记录,如下:  
            A,       B,       C  
  值为      a1,     b1,     c1       –a1分组的第一条记录。  
            a2,     b2,     c2       –a2分组的第一条记录。  
            a3,     b4,     c4       –a3分组的第一条记录。

select   *   from   表   tem   where   c=(select   top   1   c   from   表   where   a=tem.a)

现有数据表call如下:  
   
  zj                               th                   bj  
  ————-   ——–   ————-  
  03106666666 00001 03101111111  
  13711111111 00001 031122222222  
  03108898888 950000  
  031177778777 950000  
  031155955555 00001 031187888876  
   
  注:th如为950000,则bj为空,th如为00001,则bj不是空。  
   
  1、bj分组  
  select   substr(bj,1,4)   as   区号,count(*)   as   呼叫总量   from   call  
  group   by   substr(bj,1,4);  
  执行结果  
   
  区号                         呼叫总量  
  ————     ————–  
  0310                           1  
  0311                           2  
                                    2              
   
  2、zj分组,条件是th为950000的记录  
  select   substr(zj,1,4)   as   区号,count(*)   as   呼叫总量   from   call  
  where   th=950000  
  group   by   substr(zj,1,4);  
  执行结果:  
   
  区号                         呼叫总量  
  ————     ————–  
  0310                           1  
  0311                           1  
   
  能否有一个语句就能实现如下结果:  
   
  区号                         呼叫总量  
  ————     ————–  
  0310                           2  
  0311                           3  
   
  注:想要得到结果是1对应的行加2对应的行。

union起来再求和  
  select   区号,sum(呼叫总量)   from    
  (select   substr(bj,1,4)   as   区号,count(*)   as   呼叫总量   from   call  
  group   by   substr(bj,1,4))  
  union   all  
  (select   substr(zj,1,4)   as   区号,count(*)   as   呼叫总量   from   call  
  where   th=950000  
  group   by   substr(zj,1,4))  
  group   by   区号;

这个应该在Oracle中运行

select    
          decode(th,’950000′,substr(zj,1,4),substr(bj,1,4))   as   区号,  
          count(*)   as   呼叫总量    
from    
          call  
group   by  
          decode(th’950000′,substr(zj,1,4),substr(bj,1,4))

decode(条件,值1,翻译值1,值2,翻译值2,…值n,翻译值n,缺省值)

该函数的含义如下:

IF 条件=值1 THEN
    RETURN(翻译值1)
ELSIF 条件=值2 THEN
    RETURN(翻译值2)
    ……
ELSIF 条件=值n THEN
    RETURN(翻译值n)

ELSE
    RETURN(缺省值)
END IF

 

例子8:在SQL Server2005/2008中对记录进行分组,并获得每组前N条记录
假设有一个表,SQL语句如下:
  
CREATE TABLE [dbo].[scan](
    [km] [int] NULL,
    [kh] [int] NULL,
    [cj] [int] NULL
) ON [PRIMARY]

    其中km为科目号、kh为考生号、cj为成绩,现对km和kh进行分组,并获得每组前2条记录(按cj从高到低排序)。基本思想是为每组加一个序号列,再用where取序号小于等于2的。SQL语句如下:
select * from
(
    select a.km,a.kh,cj,row_number() over(partition by a.km order by a.km,a.cj desc) n
    from
        (select km,kh,SUM(cj) cj from scan group by km,kh) a
) b where n<=2  order by km, cj desc

最后得到的结果集如下图所示。

例子9:如何实现分组Group取前N条记录的sql语句
在表A中根据字段B分组、根据字段C排序并查询出每组中的前三条记录,查询结果要求包含所有字段,请问sql语句该怎么写?下面的sql语句虽然可以实现,但由于数据量比较大,耗费时间太长,有没有不通过表联接而直接分组取记录的方法呢?多谢!
select *
from 表A as t1
where 主键 in(
select top 3 主键
from 表A as t2
where t1.B=t2.B
order by t2.C)

注释  (隐藏注释)
答案1
作者:邹建

select id=identity(int,1,1),b, 主键 into # from 表A order by B,C

select a.*
from 表A a, # b,(select id1=min(id),id2=min(id)+2 from # group by b)c
where a.主键=b.主键
and b.id between c.id1 and c.id2

drop table #

答案2
作者:aierong

求每组前2名,你有几种方法?(MS SQL2000)

create table abc(
i nvarchar(10),
ii int,
iii int,
iiii int,
price money)
Go
insert into abc
select ‘b’,1,2,1,11
union all
select ‘b’,211,2,1,211
union all
select ‘a’,21,2,1,311
union all
select ‘d’,41,42,1,411
union all
select ‘d’,41,42,1,511
union all
select ‘d’,41,42,1,611
union all
select ‘e’,1,2,1,11
union all
select ‘e’,71,2,1,31
union all
select ‘e’,61,2,1,911
union all
select ‘e’,771,2,1,1
go

要求的结果是:
以i分组,求每组price最大的前2条记录

i ii iii iiii price
———- ———– ———– ———– ———————
a 21 2 1 311.0000
b 1 2 1 11.0000
b 211 2 1 211.0000
d 41 42 1 511.0000
d 41 42 1 611.0000
e 71 2 1 31.0000
e 61 2 1 911.0000

1.
select *
from abc a
where (
select counthttp://dev1.haocang.com:8080/kb/images/icons/emoticons/star_yellow.gif from abc b
where a.i=b.i and b.price>a.price)<2
order by i,price

连接查询,判断数量

2.
select i,ii,iii,iiii,price
from (
select (select isnull(sum(1),0)+1 from abc b where a.i=b.i and a.price<b.price) ids,*
from abc a) tem
where ids<3
order by i,price

生产一个内部表,给内部表tem中的每一组排序,并把排序号放入新列ids中

3.
declare @looptime int
declare @count int
declare @i nvarchar(10)
/定义表变量@abc,和表ABC中的所有列类型相同/
declare @abc table(
i nvarchar(10),
ii int,
iii int,
iiii int,
price money)
declare @tem table(
ids int identity,
class nvarchar(10))
/把表ABC中的所有组全部查询出来,暂时存在表变量@tem中/
insert into @tem(class)
select i
from abc
group by i
/求出表变量@tem中行数量/
select @count=@@rowcount
/循环变量@looptime赋初值=1/
select @looptime=1
while(@looptime<=@count)
begin
/将每组名赋值到变量@i/
select @i=class
from @tem
where ids=@looptime
/将每组前2名插入到表变量@abc中/
insert into @abc
select top 2 *
from abc
where i=@i
order by price desc
/循环变量@looptime累加1/
select @looptime=@looptime+1
end
/显示结果/
select *
from @abc
order by i,price

4.
用游标来处理
方法和我的第3种方法类似,大家可以自己试试

我共写了4种,不知道大家还有什么其他好方法,可以交流,谢谢。

今天用到了,利用此方法可以解决一个删除重复记录的问题

当然表必须带有唯一索引,仔细看以下代码

Delete From dbo.TB_WorkflowTask a
 WHERE  ItemID Not in( select top 1 ItemID from TB_WorkflowTask where TaskName=a.TaskName And EmpID = a.EmpID And BillTypeID =a.BillTypeID And BillID = a.BillID And Status =a.Status AND WFStatus =a.WFStatus )

注意:只能用 In 或 Not in ,不能用Exists 或 Not Exists ,至于为什么,大家思考一下?

例子10:如何取得分组后最后一条记录的值?
 

还是很混乱,再排一下:

重新整理一下格式:

现有一表 Log: Day In Out Current
  2012.4.5 10 0 10
  2012.4.5 0 5 5
  2012.4.6 30 20 15
  2012.4.6 0 3 12

  ………………………………………………

希望显示为

  2012.4.5 10 5 5
  2012.4.6 30 23 12

SQL code
with tb as(
select [day],sum([in]) as [in],sum(out) as out,sum([in])-sum(out) as [current],rank() over( order by [day]) as row from [log] group by [day]
)
select [day],[in],out,(select sum([current]) from tb b where b.row<=a.row)[current] from tb a
 
 
SQL code
2012.4.5    10    5    5
2012.4.6    30    23    12
 
SQL code
 
–> 测试数据:[Log]
if object_id(‘[Log]’) is not null drop table [Log]
create table [Log]([Day] date,[In] int,[Out] int,[Current] int)
insert [Log]
select ‘2012.4.5’,10,0,10 union all
select ‘2012.4.5’,0,5,5 union all
select ‘2012.4.6’,30,20,15 union all
select ‘2012.4.6’,0,3,12
 
select
[Day],sum([In]) [In],sum([Out]) [Out],min([Current]) as [Current]
from [Log] group by [Day]
 
/*
Day    In    Out    Current
2012-04-05    10    5    5
2012-04-06    30    23    12
*/
 
例子11:sql分组后二次汇总

国家(country) 人口(population) 中国 600 美国 100 加拿大 100 英国 200 法国 300 日本 250 德国 200 墨西哥 50 印度 250

根据这个国家人口数据,统计亚洲和北美洲的人口数量。应该得到下面这个结果。

人口
亚洲 1100
北美洲 250
其他 700

代码

SELECT SUM(population),
CASE country
WHEN ‘中国’ THEN ‘亚洲’
WHEN ‘印度’ THEN ‘亚洲’
WHEN ‘日本’ THEN ‘亚洲’
WHEN ‘美国’ THEN ‘北美洲’
WHEN ‘加拿大’ THEN ‘北美洲’
WHEN ‘墨西哥’ THEN ‘北美洲’
ELSE ‘其他’ END
FROM Table_A
GROUP BY CASE country
WHEN ‘中国’ THEN ‘亚洲’
WHEN ‘印度’ THEN ‘亚洲’
WHEN ‘日本’ THEN ‘亚洲’
WHEN ‘美国’ THEN ‘北美洲’
WHEN ‘加拿大’ THEN ‘北美洲’
WHEN ‘墨西哥’ THEN ‘北美洲’
ELSE ‘其他’ END;

同样的,我们也可以用这个方法来判断工资的等级,并统计每一等级的人数。SQL代码如下;

SELECT
CASE WHEN salary <= 500 THEN ‘1’
WHEN salary > 500 AND salary <= 600 THEN ‘2’
WHEN salary > 600 AND salary <= 800 THEN ‘3’
WHEN salary > 800 AND salary <= 1000 THEN ‘4’
ELSE NULL END salary_class,
COUNT(*)
FROM Table_A
GROUP BY
CASE WHEN salary <= 500 THEN ‘1’
WHEN salary > 500 AND salary <= 600 THEN ‘2’
WHEN salary > 600 AND salary <= 800 THEN ‘3’
WHEN salary > 800 AND salary <= 1000 THEN ‘4’
ELSE NULL END;

对于groupby后面一般都是跟一个列名,但在该例子中通过case语句使分组变得跟强大了。

实例三

有如下数据

国家(country) 性别(sex) 人口(population)
中国 1 340
中国 2 260
美国 1 45
美国 2 55
加拿大 1 51
加拿大 2 49
英国 1 40
英国 2 60

按照国家和性别进行分组,得出结果如下

国家
中国 340 260
美国 45 55
加拿大 51 49
英国 40 60

代码

SELECT country,
SUM( CASE WHEN sex = ‘1’ THEN
population ELSE 0 END), –男性人口
SUM( CASE WHEN sex = ‘2’ THEN
population ELSE 0 END) –女性人口
FROM Table_A
GROUP BY country;

GROUP BY子句中的NULL值处理
当GROUP BY子句中用于分组的列中出现NULL值时,将如何分组呢?SQL中,NULL不等于NULL(在WHERE子句中有过介绍)。然而,在GROUP BY子句中,却将所有的NULL值分在同一组,即认为它们是“相等”的。

HAVING子句
GROUP BY子句分组,只是简单地依据所选列的数据进行分组,将该列具有相同值的行划为一组。而实际应用中,往往还需要删除那些不能满足条件的行组,为了实现这个功能,SQL提供了HAVING子句。语法如下。

SELECT column, SUM(column)
FROM table
GROUP BY column
HAVING SUM(column) condition value

说明:HAVING通常与GROUP BY子句同时使用。当然,语法中的SUM()函数也可以是其他任何聚合函数。DBMS将HAVING子句中的搜索条件应用于GROUP BY子句产生的行组,如果行组不满足搜索条件,就将其从结果表中删除。

HAVING子句的应用
从TEACHER表中查询至少有两位教师的系及教师人数。

实现代码:

SELECT DNAME, COUNT(*) AS num_teacher
FROM TEACHER
GROUP BY DNAME
HAVING COUNT(*)>=2

HAVING子句与WHERE子句的区别

HAVING子句和WHERE子句的相似之处在于,它也定义搜索条件。但与WHERE子句不同,HAVING子句与组有关,而不是与单个的行有关。
1、如果指定了GROUP BY子句,那么HAVING子句定义的搜索条件将作用于这个GROUP BY子句创建的那些组。
2、如果指定WHERE子句,而没有指定GROUP BY子句,那么HAVING子句定义的搜索条件将作用于WHERE子句的输出,并把这个输出看作是一个组。
3、如果既没有指定GROUP BY子句也没有指定WHERE子句,那么HAVING子句定义的搜索条件将作用于FROM子句的输出,并把这个输出看作是一个组。
4、在SELECT语句中,WHERE和HAVING子句的执行顺序不同。在本书的5.1.2节介绍的SELECT语句的执行步骤可知,WHERE子句只能接收来自FROM子句的输入,而HAVING子句则可以接收来自GROUP BY子句、WHERE子句和FROM子句的输入。


数据运维技术 » 分组后分组合计以及总计SQL语句(稍微整理了一下)