Sql 2000 中行转列的查询方法
2007-08-08 17:58
295 查看
发现问题
先建立一张准备查询的报表。
CREATE
TABLE [TempTable]
(
[Id] INT
IDENTITY(1,1)
NOT
NULL,
-- 分为1 2 3 4 5 种类型
[Type] INT
NOT
NULL,
-- 纪录不同类型的操作备注
[Note] NVARCHAR(100)
NULL,
-- 增加的时间
[AddDateTime] DATETIME
NULL,
CONSTRAINT [PK_TempTable_Id] PRIMARY
KEY
CLUSTERED
(
[Id] ASC
)
WITH
(IGNORE_DUP_KEY
=
OFF)
ON [PRIMARY]
)
ON [PRIMARY]
然后往里面插入一些临时的数据(插入时,预留一些类型是没有数据的)。
INSERT
INTO [TempTable]
VALUES(1,'操作',GETDATE())
INSERT
INTO [TempTable]
VALUES(1,'操作',GETDATE())
INSERT
INTO [TempTable]
VALUES(1,'操作',GETDATE())
INSERT
INTO [TempTable]
VALUES(1,'操作',GETDATE())
INSERT
INTO [TempTable]
VALUES(3,'操作',GETDATE())
INSERT
INTO [TempTable]
VALUES(3,'操作',GETDATE())
INSERT
INTO [TempTable]
VALUES(3,'操作',GETDATE())
现在我们要这样来统计数据,
如果拿到这样的结果,一开始会想到使用连接查询来查数据。
SELECT
COUNT(1)
AS [1] FROM [dbo].[TempTable] WHERE [Type] = 1 GROUP
BY [Type]
这样先查询出一个类型的数据,之后再组合起来。
SELECT
[1].[1],
[2].[2],
[3].[3],
[4].[4],
[5].[5]
FROM
(SELECT
COUNT(1)
AS [1] FROM [dbo].[TempTable] WHERE [Type] = 1 GROUP
BY [Type])
AS [1]
,
(SELECT
COUNT(1)
AS [2] FROM [dbo].[TempTable] WHERE [Type] = 2 GROUP
BY [Type])
AS [2]
,
(SELECT
COUNT(1)
AS [3] FROM [dbo].[TempTable] WHERE [Type] = 3 GROUP
BY [Type])
AS [3]
,
(SELECT
COUNT(1)
AS [4] FROM [dbo].[TempTable] WHERE [Type] = 4 GROUP
BY [Type])
AS [4]
,
(SELECT
COUNT(1)
AS [5] FROM [dbo].[TempTable] WHERE [Type] = 5 GROUP
BY [Type])
AS [5]
以为这样大功告成了,可是查询出来的结果却发现没有值,这是因为有的类型里面是没有数据的(开始预插入数据也就是为了这点)。
为什么没有数据显示呢?
在Sql中如果我们Count(*)一个数据表一般是有数据返回的,没有数据则为0,不过如果我们在查询语句后面加了Group By 的话,那么查询条件的值没有数据,那么分组就不会返回任何数据。
这样就导致了上面最原始的方式来进行行转列的方式失效了。
问题可以解决了吗?
仔细想想,其实就是没有数据的时候,就不能返回值,那么只需要在没有值的情况下,我们自己加一个NULL值进去不就好了吗,于是可以把没有值的类型这样来写:
SELECT
COUNT(*)
- 1
FROM
(
SELECT
[Type]
FROM
[TempTable]
WHERE
[Type] = 2
UNION ALL
SELECT
NULL
)
AS [Temp]
WHERE
[Type] IS
NULL
GROUP
BY
[Type]
这样查询出来的结果就可以为 0 了,不过问题又出现了,那我怎么能知道这个类型什么时候有数据,什么时候又没呢?那样不是需要写IF判断了吗?这样就不是一个单独的SELECT语句能办到的事情了。
寻找突破口
其实要有一个高效率的查询,还是做子查询的效率高,既然是按Type来进行查询,对它进行分组,那么我们可以把Type提出来作为一个类型表,然后根据这个类型表与此表做子查询,马上就可以得出结果。
首先创建一个Type表
CREATE
TABLE [TempTableType]
(
[Id] INT
IDENTITY(1,1)
NOT
NULL,
-- 分为1 2 3 4 5 种类型
[TypeName] NVARCHAR(10) NOT
NULL
CONSTRAINT [PK_TempTableType_Id] PRIMARY
KEY
CLUSTERED
(
[Id] ASC
)
WITH
(IGNORE_DUP_KEY
=
OFF)
ON [PRIMARY]
)
ON [PRIMARY]
插入类型数据:
INSERT
INTO [TempTableType]
VALUES('1')
INSERT
INTO [TempTableType]
VALUES('2')
INSERT
INTO [TempTableType]
VALUES('3')
INSERT
INTO [TempTableType]
VALUES('4')
INSERT
INTO [TempTableType]
VALUES('5')
然后通过下面的语句就可以查出来对应类型的数量总计:
SELECT
[TypeName],
(
SELECT
COUNT(*)
FROM [TempTable] WHERE [TypeName] = [Type]
)
AS [Sum]
FROM
[TempTableType]
然后结果 0 是不是就出来了,然后再来进行转列,就可以得到结果了。
最后的解决办法
上面的解决办法,会动用的到另外的一张表,明显的不会是一个完美的解决方案,继续一步步分析,首先我们先获取有类型的数据总计:
SELECT
[Type],
COUNT(1)
AS [Sum]
FROM
[TempTable]
GROUP
BY
[Type]
然后会得到:
如果现在要把Type = 1的时候换成列怎么显示呢?使用最开始的那种连接查询方式?这显然已经不能行的,那么还有什么方式么?对了,可以使用 CASE 分支语句:
SELECT
ISNULL(SUM(CASE [Type] WHEN 1 THEN [Sum] END), 0)
FROM
(
SELECT
[Type],
COUNT(1)
AS [Sum]
FROM
[TempTable]
GROUP
BY
[Type]
)AS [Temp]
OK 这样可以显示出 Type =1 时的结果了,因为Type=1的只有一个,其余的都会为0,这样通过Sum来计算,也等于说只把多条纪录汇总为一条,就达到了显示的结果。同理的情况我们把剩下的类型写出来:
SELECT
ISNULL(SUM(CASE [Type] WHEN 1 THEN [Sum] END), 0)
AS [Type1],
ISNULL(SUM(CASE [Type] WHEN 2 THEN [Sum] END), 0)
AS [Type2],
ISNULL(SUM(CASE [Type] WHEN 3 THEN [Sum] END), 0)
AS [Type3],
ISNULL(SUM(CASE [Type] WHEN 4 THEN [Sum] END), 0)
AS [Type4],
ISNULL(SUM(CASE [Type] WHEN 5 THEN [Sum] END), 0)
AS [Type5]
FROM
(
SELECT
[Type],
COUNT(1)
AS [Sum]
FROM
[TempTable]
GROUP
BY
[Type]
)AS [Temp]
OK,我们的查询目的达到了,CASE语句能达到这样的效果是因为它能把未能查到的条件赋值为NULL所以根据这点,就可以解决分组后Count(*)无返回值的问题。
有什么更好的方法多多交流。
先建立一张准备查询的报表。
CREATE
TABLE [TempTable]
(
[Id] INT
IDENTITY(1,1)
NOT
NULL,
-- 分为1 2 3 4 5 种类型
[Type] INT
NOT
NULL,
-- 纪录不同类型的操作备注
[Note] NVARCHAR(100)
NULL,
-- 增加的时间
[AddDateTime] DATETIME
NULL,
CONSTRAINT [PK_TempTable_Id] PRIMARY
KEY
CLUSTERED
(
[Id] ASC
)
WITH
(IGNORE_DUP_KEY
=
OFF)
ON [PRIMARY]
)
ON [PRIMARY]
然后往里面插入一些临时的数据(插入时,预留一些类型是没有数据的)。
INSERT
INTO [TempTable]
VALUES(1,'操作',GETDATE())
INSERT
INTO [TempTable]
VALUES(1,'操作',GETDATE())
INSERT
INTO [TempTable]
VALUES(1,'操作',GETDATE())
INSERT
INTO [TempTable]
VALUES(1,'操作',GETDATE())
INSERT
INTO [TempTable]
VALUES(3,'操作',GETDATE())
INSERT
INTO [TempTable]
VALUES(3,'操作',GETDATE())
INSERT
INTO [TempTable]
VALUES(3,'操作',GETDATE())
现在我们要这样来统计数据,
日期 | 类型1 | 类型2 | 类型3 | 类型4 | 类型5 | 小计 |
2007-8-8 | 4 | 0 | 3 | 0 | 0 | 6 |
如果拿到这样的结果,一开始会想到使用连接查询来查数据。
SELECT
COUNT(1)
AS [1] FROM [dbo].[TempTable] WHERE [Type] = 1 GROUP
BY [Type]
这样先查询出一个类型的数据,之后再组合起来。
SELECT
[1].[1],
[2].[2],
[3].[3],
[4].[4],
[5].[5]
FROM
(SELECT
COUNT(1)
AS [1] FROM [dbo].[TempTable] WHERE [Type] = 1 GROUP
BY [Type])
AS [1]
,
(SELECT
COUNT(1)
AS [2] FROM [dbo].[TempTable] WHERE [Type] = 2 GROUP
BY [Type])
AS [2]
,
(SELECT
COUNT(1)
AS [3] FROM [dbo].[TempTable] WHERE [Type] = 3 GROUP
BY [Type])
AS [3]
,
(SELECT
COUNT(1)
AS [4] FROM [dbo].[TempTable] WHERE [Type] = 4 GROUP
BY [Type])
AS [4]
,
(SELECT
COUNT(1)
AS [5] FROM [dbo].[TempTable] WHERE [Type] = 5 GROUP
BY [Type])
AS [5]
以为这样大功告成了,可是查询出来的结果却发现没有值,这是因为有的类型里面是没有数据的(开始预插入数据也就是为了这点)。
为什么没有数据显示呢?
在Sql中如果我们Count(*)一个数据表一般是有数据返回的,没有数据则为0,不过如果我们在查询语句后面加了Group By 的话,那么查询条件的值没有数据,那么分组就不会返回任何数据。
这样就导致了上面最原始的方式来进行行转列的方式失效了。
问题可以解决了吗?
仔细想想,其实就是没有数据的时候,就不能返回值,那么只需要在没有值的情况下,我们自己加一个NULL值进去不就好了吗,于是可以把没有值的类型这样来写:
SELECT
COUNT(*)
- 1
FROM
(
SELECT
[Type]
FROM
[TempTable]
WHERE
[Type] = 2
UNION ALL
SELECT
NULL
)
AS [Temp]
WHERE
[Type] IS
NULL
GROUP
BY
[Type]
这样查询出来的结果就可以为 0 了,不过问题又出现了,那我怎么能知道这个类型什么时候有数据,什么时候又没呢?那样不是需要写IF判断了吗?这样就不是一个单独的SELECT语句能办到的事情了。
寻找突破口
其实要有一个高效率的查询,还是做子查询的效率高,既然是按Type来进行查询,对它进行分组,那么我们可以把Type提出来作为一个类型表,然后根据这个类型表与此表做子查询,马上就可以得出结果。
首先创建一个Type表
CREATE
TABLE [TempTableType]
(
[Id] INT
IDENTITY(1,1)
NOT
NULL,
-- 分为1 2 3 4 5 种类型
[TypeName] NVARCHAR(10) NOT
NULL
CONSTRAINT [PK_TempTableType_Id] PRIMARY
KEY
CLUSTERED
(
[Id] ASC
)
WITH
(IGNORE_DUP_KEY
=
OFF)
ON [PRIMARY]
)
ON [PRIMARY]
插入类型数据:
INSERT
INTO [TempTableType]
VALUES('1')
INSERT
INTO [TempTableType]
VALUES('2')
INSERT
INTO [TempTableType]
VALUES('3')
INSERT
INTO [TempTableType]
VALUES('4')
INSERT
INTO [TempTableType]
VALUES('5')
然后通过下面的语句就可以查出来对应类型的数量总计:
SELECT
[TypeName],
(
SELECT
COUNT(*)
FROM [TempTable] WHERE [TypeName] = [Type]
)
AS [Sum]
FROM
[TempTableType]
TypeName | Sum |
1 | 4 |
2 | 0 |
3 | 3 |
4 | 0 |
5 | 0 |
最后的解决办法
上面的解决办法,会动用的到另外的一张表,明显的不会是一个完美的解决方案,继续一步步分析,首先我们先获取有类型的数据总计:
SELECT
[Type],
COUNT(1)
AS [Sum]
FROM
[TempTable]
GROUP
BY
[Type]
然后会得到:
Type | Sum |
1 | 4 |
3 | 3 |
SELECT
ISNULL(SUM(CASE [Type] WHEN 1 THEN [Sum] END), 0)
FROM
(
SELECT
[Type],
COUNT(1)
AS [Sum]
FROM
[TempTable]
GROUP
BY
[Type]
)AS [Temp]
OK 这样可以显示出 Type =1 时的结果了,因为Type=1的只有一个,其余的都会为0,这样通过Sum来计算,也等于说只把多条纪录汇总为一条,就达到了显示的结果。同理的情况我们把剩下的类型写出来:
SELECT
ISNULL(SUM(CASE [Type] WHEN 1 THEN [Sum] END), 0)
AS [Type1],
ISNULL(SUM(CASE [Type] WHEN 2 THEN [Sum] END), 0)
AS [Type2],
ISNULL(SUM(CASE [Type] WHEN 3 THEN [Sum] END), 0)
AS [Type3],
ISNULL(SUM(CASE [Type] WHEN 4 THEN [Sum] END), 0)
AS [Type4],
ISNULL(SUM(CASE [Type] WHEN 5 THEN [Sum] END), 0)
AS [Type5]
FROM
(
SELECT
[Type],
COUNT(1)
AS [Sum]
FROM
[TempTable]
GROUP
BY
[Type]
)AS [Temp]
Type1 | Type2 | Type3 | Type4 | Type5 |
4 | 0 | 3 | 0 | 0 |
有什么更好的方法多多交流。
相关文章推荐
- Sql 2000 中行转列的查询方法
- microsoft sqlserver 2000查询版本号的方法
- sql 2000 无法执行查询,因为一些文件缺少或未注册"的解决方法
- sql 2000 无法执行查询,因为一些文件缺少或未注册"的解决方法
- SQL查询表是否存在的两种方法
- sql 多条件查询的一种简单的方法
- Hibernate通过SQL查询常量时只能返回第一个字符的解决方法
- sql查询重复记录、删除重复记录方法大全
- 《提高SQL查询效率的30种方法》
- sql语句查询出表里符合条件的第二条记录的方法
- MS sqlserver 2008数据库转换成2000版本的方法
- SQL Server 2000 之SQL语言编程内容提要之三SQL语言查询功能讨论
- 数据统计例子,相关子查询!(SQL 中循环操作一列数据方法)
- 查询SQL连接数的方法
- 【职坐标】Mysql中查询SQL优化的常用方法(一)
- SQL重复记录查询的几种方法
- sql查询重复记录、删除重复记录方法大全
- SQL查询语句通配符与ACCESS模糊查询like的解决方法
- 用SQL查询数据库中某一字段下相同值的记录方法
- 提高SQL查询效率的30种方法