请教高手:应该怎样构造这样的存储过程?

trybird 2000-03-12 05:17:00
有两个多对多关系的表,就比如象NT登录时的用户组和用户之间的关系吧——
一个用户组可以包含多个用户,同样,一个用户也可以属于多个用户组。

用户组表(Group)可以这样:

Group_ID Group_Name Right ...

123 Admin 1111
110 Guest 1000
119 Global 1010
...

用户表(User)可以这样:

User_ID User_Name ...

001 John
002 Tom
003 Welson
004 Jane
005 Charlie
...

成员表(Member)则用来表示它们的多对多关系:

Group_ID User_ID
123 001
110 001
110 002
110 003
119 002
119 004
119 005
...

现在想构建一个Stored Procedure,使其返回如下形式的结果集:

Group_ID Group_Name User_List Right

123 Admin John ...
110 Guest John,Tom,Welson ...
119 Global Tom,Jane,Charlie ...
...

注意:如意是单用户的组就只在User_List列把那个用户名列出,
多个用户的组在User_List列把所有用户均列出,用户名之间以逗号分隔开。

请各位高手教我,应该怎样最简便地写这个存储过程?————

create procedure pro_usrlist
as
...

(另:以上是返回全部用户组的,如果带输入参数,只想返回指定用户组的,
又该如何构造?)
...全文
487 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
tanghuan 2000-03-30
  • 打赏
  • 举报
回复
用游标的速度很慢
在15000条数据的情况下,游标要几小时
create procedure pro_name
(
@FindGoup char(30)="%"
)
as
begin
create table #temptable (Group_ID char(5),
Group_Name char(5),
User_List char(255)/*假设可以存下所有用户*/ )
select * into #tempMember from Member where 1=2
declare @Group_ID char(5),@User_ID char(5)
select *
into #tempGroup
from Group
where Group_Name like @FindGoup
select @Group_ID =""
while (1=1)
begin
select @Group_ID=min(Group_ID)
from (select Group_ID from Group where Group_ID>@Group_ID)
if @@RowCount=0
break
insert into #temptable values(Group_ID ,Group_Name )
select Group_ID ,Group_Name
from Group
where Group_ID =@Group_ID
delete #tempMember
insert into #tempMember
select *
from Member
where Group_ID =@Group_ID
select @User_ID=""
while
begin
select @User_ID=min(User_ID)
from (select User_ID
from #tempMember
where @User_ID>User_ID) a
if @@RowCount=0
break
update #tempTable set #tempTable.User_List =
#tempTable.User_List + "," +User.UserName
from #tempTable,User
where #tempTable.Group_ID=@Group_ID and
User.User_ID=@User_ID

end

end
select * from #tempTable
end
trybird 2000-03-23
  • 打赏
  • 举报
回复
望各位大侠能帮我,优化精炼以上SP,或写出更精彩出色的原码来!

我好买单!
trybird 2000-03-23
  • 打赏
  • 举报
回复
带参数的SP——

create procedure pro_grpusr
(@grpname varchar(30))
as
declare @pt_grpid varchar(3),@pt_usrname varchar(30),@grpid varchar(3),@usrname varchar(30)
declare cur_member scroll cursor
for
select member.group_id,users.usr_name from member inner join users
on member.usr_id=users.usr_id
order by member.group_id
open cur_member
fetch first from cur_member
into @grpid,@usrname
set @pt_grpid=''
set @pt_usrname=''
create table #usrlst
(group_id varchar(11),
userlist varchar(30))
while(@@FETCH_STATUS=0)
begin
if(@pt_grpid<>@grpid)
begin
if(@pt_grpid<>'')
begin
insert #usrlst
values(@pt_grpid,@pt_usrname)
end
set @pt_grpid=@grpid
set @pt_usrname=''
end
if(@pt_usrname='')
begin
set @pt_usrname=@usrname
end
else
begin
set @pt_usrname=@pt_usrname+','+@usrname
end
fetch next from cur_member
into @grpid,@usrname
end
insert #usrlst
values(@pt_grpid,@pt_usrname)
close cur_member
deallocate cur_member
select distinct groups.group_id,groups.group_name,#usrlst.userlist,groups.rights
from groups inner join #usrlst
on groups.group_id=#usrlst.group_id
where groups.group_name=@grpname
drop table #usrlst
trybird 2000-03-23
  • 打赏
  • 举报
回复
不带参数的SP——

create procedure pro_usrlist as
declare @pt_grpid varchar(3),@pt_usrname varchar(30),@grpid varchar(3),@usrname varchar(30)
declare cur_member scroll cursor
for
select member.group_id,users.usr_name from member inner join users
on member.usr_id=users.usr_id
order by member.group_id
open cur_member
fetch first from cur_member
into @grpid,@usrname
set @pt_grpid=''
set @pt_usrname=''
create table #usrlst
(group_id varchar(11),
userlist varchar(30))
while(@@FETCH_STATUS=0)
begin
if(@pt_grpid<>@grpid)
begin
if(@pt_grpid<>'')
begin
insert #usrlst
values(@pt_grpid,@pt_usrname)
end
set @pt_grpid=@grpid
set @pt_usrname=''
end
if(@pt_usrname='')
begin
set @pt_usrname=@usrname
end
else
begin
set @pt_usrname=@pt_usrname+','+@usrname
end
fetch next from cur_member
into @grpid,@usrname
end
insert #usrlst
values(@pt_grpid,@pt_usrname)
close cur_member
deallocate cur_member
select distinct groups.group_id,groups.group_name,#usrlst.userlist,groups.rights
from groups inner join #usrlst
on groups.group_id=#usrlst.group_id
drop table #usrlst
trybird 2000-03-23
  • 打赏
  • 举报
回复
可能占用了一些SQL Server关键字,将建表命令重新更正一下——

create table groups
(group_id varchar(3) constraint PK_grp primary key clustered,
group_name varchar(30) not NULL,
rights varchar(4))

go

create table users
(usr_id varchar(3) constraint PK_usr primary key clustered,
usr_name varchar(30) not NULL)

go

create table member
(group_id varchar(3) constraint FK_mem_grp
foreign key references groups(group_id),
usr_id varchar(3) constraint FK_mem_usr
foreign key references users(usr_id),
constraint PK_mem primary key(group_id,usr_id))

go
trybird 2000-03-21
  • 打赏
  • 举报
回复
:-D
trybird 2000-03-21
  • 打赏
  • 举报
回复
请原码教我!

我也会乐意痛痛快快买单的!
trybird 2000-03-21
  • 打赏
  • 举报
回复
我想每一个如我一般的菜鸟都希望能得到象WHQ大侠那样的回复吧——
WHQ的大侠风范,高手气派,蔼然可亲,肃然可敬!
如下——————

我想写一个触发器,作用是修改表的时候让PRIMARY字段自动+1,就想ACCESS一样。由于从来没有写过触发器,请指教。
另外一个问题,哪里有关于SQL SERVER编程的中文教材,929你不要回答了,你给我的主页的确有很多好书...名:),连接全错了:(。

Re:触发器问题 WHQ 2000-3-13 19:41:39 20
Create TRIGGER AutoIncreate ON INSERT
DECLARE @ID AS INTEGER;
SELECT @ID = select max(ID)+1 from Table; // ID为需要自动加1的字段名
update table set ID = @ID WHERE ID = inserted.ID

Re:触发器问题 King 2000-3-13 19:43:40 0
买单:)

Re:触发器问题 lixq 2000-3-16 22:06:56 0
我以前也碰到过这个问题,因不会用触发器。费了老大劲也没理想地解决。这可解决大问题了。真高兴!

trybird 2000-03-21
  • 打赏
  • 举报
回复
此问题来自实际,相信能有不少人早已经遇到并解决了——
我的实际SP其实比这要复杂得多,但为了大家好理解我用NT用户组简化了——
我再打个比方——
比如很多人一起干同一件事,算工时算收益,你就必须这样列明才清晰。
而不能每个人都占一行。
在前端当然怎么做都能实现,不过那样我得多写很多,并且绝对不会有做成存储过程好。
望大家继续赐教,我好打分。
分虽不多,现在这情形,实在难以给分。
trybird 2000-03-21
  • 打赏
  • 举报
回复
谢谢诸位大侠!
不过我仍有些淡淡的失望。
其实问完问题的那个上午我已经把那个存储过程做出来了——
只不过深知自已太菜了。
不好意思出来现丑。
一直想学习学习大侠们的妙招。
可惜就是没有人提供源码!
我当然也是用光标做的,不过我只用了一个光标。
对于haihong大侠,我当时也有同none大侠一样的疑问:
两个光标,只有一个@@fetch_status,会不会乱套?
另外,我设问时已相当明确要存储过程原码,即使Oralce也应有原码吧?
我希望诸位大侠用完整的原码教我,多谢!

none 2000-03-14
  • 打赏
  • 举报
回复
要用MS的OLAP,这个问题就好解决了。

如果用存储过程,我的思路是:
先建一个存储过程可以将某表的某个字符列的值串在一起返回
然后再建一个存储过程,针对不重复的group_id调用先前的存储过程
最后将结果写入临时表

至haihong:
两个光标,只有一个@@fetch_status,会不会乱套?
haihong 2000-03-13
  • 打赏
  • 举报
回复
建两个cursor,
select * from group;
select user_name from user,member where user.user_id=member.user_id
and member.group_id=第一个光标选出来的group_id.
第二个cursor套在第一个里
用变量把选出的user_name拼起来
然后将cursor1的Group_ID Group_Name Right和cursor2产生的变量(user_list)
插如一个临时表(事先建好)
select * from 临时表
由于手头没装sql_server,所以没有调,oracle下可以的
trybird 2000-03-13
  • 打赏
  • 举报
回复
(O)(O)
and
O
forgettor 2000-03-13
  • 打赏
  • 举报
回复
..
929 2000-03-13
  • 打赏
  • 举报
回复
其实我觉得你的要求就是要把这三个表关联,然后以GROUPID,GROUPNAME,RIGHT进行分组,只不过结果中原来放于多条记录中USERNAME现在要用字符串连接起来形成一条。昨天我试了一下,用存储过程还没成功。但我想这在客户端用程序做应该可以实现。首先分组得到结果,在于一个结果集中。然后字符串连接把多条记录中的USERNAME连起来。再把结果进行显示。
请问一定要全部用存储过程完成吗?我再试试。
E 2000-03-13
  • 打赏
  • 举报
回复
用cursor可以,但不知不用cursor可不可以?
trybird 2000-03-12
  • 打赏
  • 举报
回复
先把建表命令给出吧——
再请各位看怎样构造存储过程——
create procedure pro_usrlist
as
...

可能确实不太容易?

/*
create database usrmng
on
primary
(name=usrmng_data,
filename='c:\Program Files\um\data\usrmng.mdf',
size=5MB,
maxsize=20MB,
filegrowth=10%)
log on
(name=usrmng_log,
filename='c:\Program Files\um\data\usrmng.ldf',
size=2MB,
maxsize=10MB,
filegrowth=1MB)

go

use usrmng

*/

create table group
(group_id varchar(3) constraint PK_grp primary key clustered,
group_name varchar(30) not NULL,
right varchar(4))

go

create table user
(user_id varchar(3) constraint PK_usr primary key clustered,
user_name varchar(30) not NULL)

go

create table member
(group_id varchar(3) constraint FK_mem_grp foreign key
references group(group_id),
user_id varchar(3) FK_mem_usr foreign key references user(user_id),
constraint PK_mem primary key(group_id,user_id))

go

34,576

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server相关内容讨论专区
社区管理员
  • 基础类社区
  • 二月十六
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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