sql高手请指教

ronaldoking9 2008-01-10 02:16:33
现在要做一个报表,表的基本结构是这样的
员工 员工号 部门 记录日期 记录时间

每天一个员工可能要多次记录,现在要产生这样的数据集

员工 员工号 部门 记录日期 当天记录时间1 当天记录时间2 当天记录时间3 当天记录时间4 .......
张三 10 人事部 20080110 075654 080909 153000 230000
张三 10 人事部 20080111 074054 084950 163000 220000
张三 10 人事部 20080111 074054 084950 163000 220000
张三 10 人事部 20080111 074054 084950 163000 220000
.
.
.
.
请问该如何做?
...全文
295 39 打赏 收藏 转发到动态 举报
写回复
用AI写文章
39 条回复
切换为时间正序
请发表友善的回复…
发表回复
prcgolf 2008-01-16
  • 打赏
  • 举报
回复
up
-狙击手- 2008-01-14
  • 打赏
  • 举报
回复
1------------------------------------------------
--游标不是明智的选择,在小数据量时可以使用
create procedure hahaha
@sqlstr nvarchar(4000), --查询字符串
@currentpage int, --第N页
@pagesize int --每页行数
as
set nocount on
declare @P1 int, --P1是游标的id
@rowcount int
exec sp_cursoropen @P1 output,@sqlstr,@scrollopt=1,@ccopt=1,@rowcount=@rowcount output
select ceiling(1.0*@rowcount/@pagesize) as 总页数--,@rowcount as 总行数,@currentpage as 当前页
set @currentpage=(@currentpage-1)*@pagesize+1
exec sp_cursorfetch @P1,16,@currentpage,@pagesize
exec sp_cursorclose @P1
set nocount off

测试: hahaha '任何条件的SQL语句',2,10
ronaldoking9 2008-01-14
  • 打赏
  • 举报
回复
就是因为是用你所贴的使用系统存储过程实现的通用分页存储过程 sp_PageView
所引发的报错,该如何解决?
ronaldoking9 2008-01-14
  • 打赏
  • 举报
回复
楼上的,我本来就是用你说的那种啊,报错如下
不允许对具有不止一条 SELECT 语句的远程存储过程或存储过程使用服务器游标。请使用默认结果集或客户端游标。
dawugui 2008-01-14
  • 打赏
  • 举报
回复
--使用系统存储过程实现的通用分页存储过程
CREATE PROC sp_PageView
@sql ntext, --要执行的sql语句
@PageCurrent int=1, --要显示的页码
@PageSize int=10, --每页的大小
@PageCount int OUTPUT --总页数
AS
SET NOCOUNT ON
DECLARE @p1 int
--初始化分页游标
EXEC sp_cursoropen
@cursor=@p1 OUTPUT,
@stmt=@sql,
@scrollopt=1,
@ccopt=1,
@rowcount=@PageCount OUTPUT

--计算总页数
IF ISNULL(@PageSize,0)<1
SET @PageSize=10
SET @PageCount=(@PageCount+@PageSize-1)/@PageSize
IF ISNULL(@PageCurrent,0)<1 OR ISNULL(@PageCurrent,0)>@PageCount
SET @PageCurrent=1
ELSE
SET @PageCurrent=(@PageCurrent-1)*@PageSize+1

--显示指定页的数据
EXEC sp_cursorfetch @p1,16,@PageCurrent,@PageSize

--关闭分页游标
EXEC sp_cursorclose @p1
dawugui 2008-01-14
  • 打赏
  • 举报
回复
-- 字符串缓存实现的通用分页存储过程(转)
CREATE PROC sp_PageView
@tbname sysname, --要分页显示的表名
@FieldKey sysname, --用于定位记录的主键(惟一键)字段,只能是单个字段
@PageCurrent int=1, --要显示的页码
@PageSize int=10, --每页的大小(记录数)
@FieldShow nvarchar(1000)='', --以逗号分隔的要显示的字段列表,如果不指定,则显示所有字段
@FieldOrder nvarchar(1000)='', --以逗号分隔的排序字段列表,可以指定在字段后面指定DESC/ASC
用于指定排序顺序
@Where nvarchar(1000)='', --查询条件
@PageCount int OUTPUT --总页数
AS
DECLARE @sql nvarchar(4000)
SET NOCOUNT ON
--检查对象是否有效
IF OBJECT_ID(@tbname) IS NULL
BEGIN
RAISERROR(N'对象"%s"不存在',1,16,@tbname)
RETURN
END
IF OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsTable')=0
AND OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsView')=0
AND OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsTableFunction')=0
BEGIN
RAISERROR(N'"%s"不是表、视图或者表值函数',1,16,@tbname)
RETURN
END

--分页字段检查
IF ISNULL(@FieldKey,N'')=''
BEGIN
RAISERROR(N'分页处理需要主键(或者惟一键)',1,16)
RETURN
END

--其他参数检查及规范
IF ISNULL(@PageCurrent,0)<1 SET @PageCurrent=1
IF ISNULL(@PageSize,0)<1 SET @PageSize=10
IF ISNULL(@FieldShow,N'')=N'' SET @FieldShow=N'*'
IF ISNULL(@FieldOrder,N'')=N''
SET @FieldOrder=N''
ELSE
SET @FieldOrder=N'ORDER BY '+LTRIM(@FieldOrder)
IF ISNULL(@Where,N'')=N''
SET @Where=N''
ELSE
SET @Where=N'WHERE ('+@Where+N')'

--如果@PageCount为NULL值,则计算总页数(这样设计可以只在第一次计算总页数,以后调用时,把总页数传回给存储过程,避免再次计算总页数,对于不想计算总页数的处理而言,可以给@PageCount赋值)
IF @PageCount IS NULL
BEGIN
SET @sql=N'SELECT @PageCount=COUNT(*)'
+N' FROM '+@tbname
+N' '+@Where
EXEC sp_executesql @sql,N'@PageCount int OUTPUT',@PageCount OUTPUT
SET @PageCount=(@PageCount+@PageSize-1)/@PageSize
END

--计算分页显示的TOPN值
DECLARE @TopN varchar(20),@TopN1 varchar(20)
SELECT @TopN=@PageSize,
@TopN1=@PageCurrent*@PageSize

--第一页直接显示
IF @PageCurrent=1
EXEC(N'SELECT TOP '+@TopN
+N' '+@FieldShow
+N' FROM '+@tbname
+N' '+@Where
+N' '+@FieldOrder)
ELSE
BEGIN
SELECT @PageCurrent=@TopN1,
@sql=N'SELECT @n=@n-1,@s=CASE WHEN @n<'+@TopN
+N' THEN @s+N'',''+QUOTENAME(RTRIM(CAST('+@FieldKey
+N' as varchar(8000))),N'''''''') ELSE N'''' END FROM '+@tbname
+N' '+@Where
+N' '+@FieldOrder
SET ROWCOUNT @PageCurrent
EXEC sp_executesql @sql,
N'@n int,@s nvarchar(4000) OUTPUT',
@PageCurrent,@sql OUTPUT
SET ROWCOUNT 0
IF @sql=N''
EXEC(N'SELECT TOP 0'
+N' '+@FieldShow
+N' FROM '+@tbname)
ELSE
BEGIN
SET @sql=STUFF(@sql,1,1,N'')
--执行查询
EXEC(N'SELECT TOP '+@TopN
+N' '+@FieldShow
+N' FROM '+@tbname
+N' WHERE '+@FieldKey
+N' IN('+@sql
+N') '+@FieldOrder)
END
END
dawugui 2008-01-14
  • 打赏
  • 举报
回复
给些例自己看.
--TOP n 实现的通用分页存储过程
CREATE PROC sp_PageView
@tbname sysname, --要分页显示的表名
@FieldKey nvarchar(1000), --用于定位记录的主键(惟一键)字段,可以是逗号分隔的多个字段
@PageCurrent int=1, --要显示的页码
@PageSize int=10, --每页的大小(记录数)
@FieldShow nvarchar(1000)='', --以逗号分隔的要显示的字段列表,如果不指定,则显示所有字段
@FieldOrder nvarchar(1000)='', --以逗号分隔的排序字段列表,可以指定在字段后面指定DESC/ASC
用于指定排序顺序
@Where nvarchar(1000)='', --查询条件
@PageCount int OUTPUT --总页数
AS
SET NOCOUNT ON
--检查对象是否有效
IF OBJECT_ID(@tbname) IS NULL
BEGIN
RAISERROR(N'对象"%s"不存在',1,16,@tbname)
RETURN
END
IF OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsTable')=0
AND OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsView')=0
AND OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsTableFunction')=0
BEGIN
RAISERROR(N'"%s"不是表、视图或者表值函数',1,16,@tbname)
RETURN
END

--分页字段检查
IF ISNULL(@FieldKey,N'')=''
BEGIN
RAISERROR(N'分页处理需要主键(或者惟一键)',1,16)
RETURN
END

--其他参数检查及规范
IF ISNULL(@PageCurrent,0)<1 SET @PageCurrent=1
IF ISNULL(@PageSize,0)<1 SET @PageSize=10
IF ISNULL(@FieldShow,N'')=N'' SET @FieldShow=N'*'
IF ISNULL(@FieldOrder,N'')=N''
SET @FieldOrder=N''
ELSE
SET @FieldOrder=N'ORDER BY '+LTRIM(@FieldOrder)
IF ISNULL(@Where,N'')=N''
SET @Where=N''
ELSE
SET @Where=N'WHERE ('+@Where+N')'

--如果@PageCount为NULL值,则计算总页数(这样设计可以只在第一次计算总页数,以后调用时,把总页数传回给存储过程,避免再次计算总页数,对于不想计算总页数的处理而言,可以给@PageCount赋值)
IF @PageCount IS NULL
BEGIN
DECLARE @sql nvarchar(4000)
SET @sql=N'SELECT @PageCount=COUNT(*)'
+N' FROM '+@tbname
+N' '+@Where
EXEC sp_executesql @sql,N'@PageCount int OUTPUT',@PageCount OUTPUT
SET @PageCount=(@PageCount+@PageSize-1)/@PageSize
END

--计算分页显示的TOPN值
DECLARE @TopN varchar(20),@TopN1 varchar(20)
SELECT @TopN=@PageSize,
@TopN1=(@PageCurrent-1)*@PageSize

--第一页直接显示
IF @PageCurrent=1
EXEC(N'SELECT TOP '+@TopN
+N' '+@FieldShow
+N' FROM '+@tbname
+N' '+@Where
+N' '+@FieldOrder)
ELSE
BEGIN
--处理别名
IF @FieldShow=N'*'
SET @FieldShow=N'a.*'

--生成主键(惟一键)处理条件
DECLARE @Where1 nvarchar(4000),@Where2 nvarchar(4000),
@s nvarchar(1000),@Field sysname
SELECT @Where1=N'',@Where2=N'',@s=@FieldKey
WHILE CHARINDEX(N',',@s)>0
SELECT @Field=LEFT(@s,CHARINDEX(N',',@s)-1),
@s=STUFF(@s,1,CHARINDEX(N',',@s),N''),
@Where1=@Where1+N' AND a.'+@Field+N'=b.'+@Field,
@Where2=@Where2+N' AND b.'+@Field+N' IS NULL',
@Where=REPLACE(@Where,@Field,N'a.'+@Field),
@FieldOrder=REPLACE(@FieldOrder,@Field,N'a.'+@Field),
@FieldShow=REPLACE(@FieldShow,@Field,N'a.'+@Field)
SELECT @Where=REPLACE(@Where,@s,N'a.'+@s),
@FieldOrder=REPLACE(@FieldOrder,@s,N'a.'+@s),
@FieldShow=REPLACE(@FieldShow,@s,N'a.'+@s),
@Where1=STUFF(@Where1+N' AND a.'+@s+N'=b.'+@s,1,5,N''),
@Where2=CASE
WHEN @Where='' THEN N'WHERE ('
ELSE @Where+N' AND ('
END+N'b.'+@s+N' IS NULL'+@Where2+N')'

--执行查询
EXEC(N'SELECT TOP '+@TopN
+N' '+@FieldShow
+N' FROM '+@tbname
+N' a LEFT JOIN(SELECT TOP '+@TopN1
+N' '+@FieldKey
+N' FROM '+@tbname
+N' a '+@Where
+N' '+@FieldOrder
+N')b ON '+@Where1
+N' '+@Where2
+N' '+@FieldOrder)
END
wzy_love_sly 2008-01-14
  • 打赏
  • 举报
回复
楼主传的@sql是:'select * from a,select * from b'这样?
ronaldoking9 2008-01-14
  • 打赏
  • 举报
回复
请看下26楼的问题,楼上的,我现在问的是26楼的问题,谢谢
dawugui 2008-01-14
  • 打赏
  • 举报
回复
declare @sql varchar(8000)
set @sql = 'select 员工,员工号,部门,记录日期'
select @sql = @sql + ' , max(case px when ''' + cast(px as varchar) + ''' then 记录时间 end) [当天记录时间' + cast(px as varchar) + ']'
from (select distinct px from (select px = (select count(*) from tb where 员工 = t.员工 and 员工号 = t.员工号 and 部门 = t.部门 and 记录日期 = t.记录日期 and 记录时间 < t.记录时间) , * from tb t ) m) as a
set @sql = @sql + ' from (select px = (select count(*) from tb where 员工 = t.员工 and 员工号 = t.员工号 and 部门 = t.部门 and 记录日期 = t.记录日期 and 记录时间 < t.记录时间) , * from tb t ) m group by 员工,员工号,部门,记录日期 order by 员工,员工号,部门,记录日期'
exec(@sql)
dawugui 2008-01-14
  • 打赏
  • 举报
回复
就是个行列转换.
ronaldoking9 2008-01-14
  • 打赏
  • 举报
回复
高手们对此都不感兴趣?快来帮帮我吧
ronaldoking9 2008-01-14
  • 打赏
  • 举报
回复
希望高手进来指教
ronaldoking9 2008-01-14
  • 打赏
  • 举报
回复
无枪狙击手请进,现在用这个查询,然后调用一个分页的存储过程出错
分页存储过程如下
CREATE PROC sp_PageView
@sql ntext, --要执行的sql语句
@PageCurrent int=1, --要显示的页码
@PageSize int=100, --每页的大小
@PageCount int OUTPUT --总页数
AS
SET NOCOUNT ON
DECLARE @p1 int
--初始化分页游标
EXEC sp_cursoropen
@cursor=@p1 OUTPUT,
@stmt=@sql,
@scrollopt=1,
@ccopt=1,
@rowcount=@PageCount OUTPUT
--计算总页数
IF ISNULL(@PageSize,0)<1
SET @PageSize=10
SET @PageCount=(@PageCount+@PageSize-1)/@PageSize
IF ISNULL(@PageCurrent,0)<1 OR ISNULL(@PageCurrent,0)>@PageCount
SET @PageCurrent=1
ELSE
SET @PageCurrent=(@PageCurrent-1)*@PageSize+1
--显示指定页的数据
EXEC sp_cursorfetch @p1,16,@PageCurrent,@PageSize
--关闭分页游标
EXEC sp_cursorclose @p1

然后我把上面的sql作为变量传进去,报以下错误:
不允许对具有不止一条 SELECT 语句的远程存储过程或存储过程使用服务器游标。请使用默认结果集或客户端游标。
春天的气息 2008-01-10
  • 打赏
  • 举报
回复
LZ这题已出现多次啦,看老贴吧!
ronaldoking9 2008-01-10
  • 打赏
  • 举报
回复
理解的头都有点发胀,高人就是高人,用了些小技巧
-狙击手- 2008-01-10
  • 打赏
  • 举报
回复
create table ta(员工 varchar(6),员工号 int,部门 varchar(10),记录日期 varchar(10),记录时间 varchar(10))
insert ta select
'张三',10,'人事部','20080110','075654' union select
'张三',10,'人事部','20080111','074054' union select
'张三',10,'人事部','20080111','084054' union select
'张三',10,'人事部','20080111','094054' union select
'张三',10,'人事部','20080111','075054' union select
'张三',10,'人事部','20080111','104054' union select
'张三',10,'人事部','20080111','114054' union select
'张三',10,'人事部','20080111','124054' union select
'张三',10,'人事部','20080111','134054' union select
'张三',10,'人事部','20080111','144054' union select
'张三',10,'人事部','20080111','155054' union select
'张三',10,'人事部','20080111','164054' union select
'张三',10,'人事部','20080111','174054' union select
'张三',10,'人事部','20080111','185054' union select
'张三',10,'人事部','20080111','194054' union select
'张三',10,'人事部','20080111','204054'union select
'张三',10,'人事部','20080111','214054' union select
'张三',10,'人事部','20080111','224054'
go
go
go
select (select count(1)+1
from ta
where 员工= a.员工 and 员工号= a.员工号 and 部门=a.部门 and 记录日期 = a.记录日期 and 记录时间 < a.记录时间 ) as px,
记录时间,员工,员工号,部门,记录日期
into ##
from ta a

declare @s varchar(8000)
set @s = 'select 员工,员工号,部门,记录日期'
select @s = @s + ',[当天记录时间'+ltrim(px)+'] = max(case when px = '''+ ltrim(px)+''' then 记录时间 else '''' end) '
from (select distinct top 15 px from ##) a
exec(@s + ' from ## group by 员工,员工号,部门,记录日期')


drop table ##,ta
/*



员工 员工号 部门 记录日期 当天记录时间1 当天记录时间2 当天记录时间3 当天记录时间4 当天记录时间5 当天记录时间6 当天记录时间7 当天记录时间8 当天记录时间9 当天记录时间10 当天记录时间11 当天记录时间12 当天记录时间13 当天记录时间14 当天记录时间15
------ ----------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
张三 10 人事部 20080110 075654
张三 10 人事部 20080111 074054 075054 084054 094054 104054 114054 124054 134054 144054 155054 164054 174054 185054 194054 204054


*/
ronaldoking9 2008-01-10
  • 打赏
  • 举报
回复
谢谢狙击手,好像可以的,分数不多见谅了,真想结交你这样的热心朋友,现在还有个问题,就是如果当天刷卡记录超过15次,第16条以后的全部忽略,如何处理?
zlp321002 2008-01-10
  • 打赏
  • 举报
回复
--try(自己可以写个循环去构造)
select 员工, 员工号,部门,记录日期,
[当天记录时间1]=[1],
[当天记录时间2]=[2],
[当天记录时间3]=[3],
[当天记录时间4]=[4],
[当天记录时间5]=[5]
from
(
select row_number() over ( order by 员工) as id,* from ta
) t
pivot
(max(记录时间)
for id in ([1],[2],[3],[4],[5])
) as pit
-狙击手- 2008-01-10
  • 打赏
  • 举报
回复
和记录的多少无关,你检查你的语句吧,少了列名 '记录时间'
加载更多回复(19)

22,209

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧