mysql存储过程 送分了。

码工码工 2009-05-20 04:26:48
统计需求:有多少本(完本)图书被完全阅读了?
mylogs表里放的是每天的阅读日志(分析Apache日志所得),book表里放的是图书的信息,比如某本书有多少章,作者,书名等等。

写了如下的存储过程,
create procedure wanbens(in d int, in m int ,in y int)
begin
declare total_nums int default 0;
declare mxindexed int default 0;
declare mxindex int default 0;
declare bid varchar(20) default '';
declare tmp_bid int default 0;
declare i int default 0;
declare wbbook_nums int default 0;

select count( distinct para_bookid ) into total_nums from mylogs where log_day=d and log_month=m and log_year=y;

while i<total_nums do

select para_bookid into bid from mylogs where para_bookid<>tmp_bid and log_day=d and log_month=m and log_year=y order by para_bookid limit 1;

if bid <> tmp_bid then
set tmp_bid = 0;
select para_bookid, para_index into tmp_bid, mxindexed from mylogs where para_bookid=bid and log_day=d and log_month=m and log_year=y order by para_index desc limit 1;

select max_chapter into mxindex from book where bookid=tmp_bid limit 1;

if mxindexed = mxindex then
set wbbook_nums = wbbook_nums+1;
end if;

end if;
set i = i+1;
set bid = 0;
end while;
select wbbook_nums;
end


但是call的时候,有死循环,谁知道为什么?以及有没有更好的办法来解决,比如使用temporary table或别的什么方法。
...全文
67 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
码工码工 2009-05-21
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 ACMAIN_CHM 的回复:]
可以用left join / right join 但没有什么意义啊。 你的读者读的书或者章节不存在?
[/Quote]

由于新旧库的原因,是有一部分书不存在,不过,这些错误的数据就不要了,所以,还是应该用inner join 万分感谢,散分。
ACMAIN_CHM 2009-05-21
  • 打赏
  • 举报
回复

可以用left join / right join 但没有什么意义啊。 你的读者读的书或者章节不存在?
码工码工 2009-05-21
  • 打赏
  • 举报
回复
但为什么是inner join呢?不是left join或right join?
码工码工 2009-05-21
  • 打赏
  • 举报
回复
ACMAIN_CHM ,强人,SQL写得漂亮,并且解决问题!谢谢了。


ACMAIN_CHM 2009-05-20
  • 打赏
  • 举报
回复
select count(distinct a.phone)
from mylogs l inner join book b on l.para_bookid=b.bookid and l.para_index=b.max_chapter
where l.log_year=year(CURDATE())
and l.log_month=month(CURDATE())
and l.log_day=day(CURDATE())


当天有3个用户读完过某本书的最后一章
ACMAIN_CHM 2009-05-20
  • 打赏
  • 举报
回复
某一天有多少本书被用户完全阅读了

select count(distinct b.bookid)
from mylogs l inner join book b on l.para_bookid=b.bookid and l.para_index=b.max_chapter
where l.log_year=year(CURDATE())
and l.log_month=month(CURDATE())
and l.log_day=day(CURDATE())


假设有书
A 20 章
B 30 单
C 50 单

当天有读书记录

userA bookA 19章
userA bookA 20章
userB bookA 20章
userB bookB 30章
userC bookA 20章
userC bookB 30章
userC bookC 40章

结果为 2 本书当天被读过最后一章了。



码工码工 2009-05-20
  • 打赏
  • 举报
回复
好的,现在第一楼的那个存储过程,我重写了下,改用游标,如下:

CREATE PROCEDURE wanbens(in d INT, in m INT ,in y INT)
BEGIN

DECLARE wbbook_nums INT;
DECLARE wbusr_nums INT;
DECLARE tmp_bid VARCHAR(20);
DECLARE tmp_phone VARCHAR(20);
DECLARE tmp_phone1 VARCHAR(20);
DECLARE mxed_index INT;
DECLARE mx_index INT;
DECLARE done INT DEFAULT 0;

DECLARE cur1 CURSOR FOR SELECT para_bookid, max(para_index) as mai, phone FROM mylogs WHERE log_day=d AND log_month=m AND log_year=y GROUP BY para_bookid HAVING mai>0;

OPEN cur1;

REPEAT

FETCH cur1 INTO tmp_bid,mxed_index,tmp_phone;

SELECT max_chapter INTO mx_index FROM book WHERE bookid LIKE CONCAT('%',tmp_bid,'%');

IF mx_index=mxed_index THEN
SET wbbook_nums = wbbook_nums + 1;
END IF;

IF tmp_phone<>tmp_phone1 THEN
SET wbusr_nums = wbusr_nums + 1;
END IF;

SET tmp_phone1 = tmp_phone;

UNTIL done END REPEAT;

CLOSE cur1;

SELECT wbbook_nums, wbusr_nums;

END



mylogs表结构:

drop table if exists mylogs;
create table mylogs (
log_year int(4) unsigned not null default 0, ##访问年
log_month int(2) unsigned not null default 0, ##月份
log_day int(2) unsigned not null default 0, ##天
log_period int(2) unsigned not null default 0, ##具体时间
phone varchar(20) not null default '', ##用户手机号
para_a varchar(100) not null default '',
para_c varchar(100) not null default '',
para_bookid varchar(100) not null default '', ##用户访问的图书ID, 存储过程做的就是从这里取出一本书ID,取出用户阅读过的最大章节ID,
##然后从book表中取出相同bookid的max_chapter,相比较,如果相同,说明该书被该用户完整
##阅读了。

para_index varchar(100) not null default '', ##用户访问过的章节ID
para_p varchar(100) not null default '',
para_x varchar(100) not null default '',
para_y varchar(100) not null default '',
para_key varchar(255) not null default '',
para_type varchar(100) not null default '',
index_access enum('yes','no') not null default 'no',
ua varchar(200) not null default ''
)
engine=myisam
default charset=utf8
partition by list(log_month) (
partition p01 values in (1),
partition p02 values in (2),
partition p03 values in (3),
partition p04 values in (4),
partition p05 values in (5),
partition p06 values in (6),
partition p07 values in (7),
partition p08 values in (8),
partition p09 values in (9),
partition p10 values in (10),
partition p11 values in (11),
partition p12 values in (12)
);

book表结构:

CREATE TABLE `book` (
`bookid` varchar(255) DEFAULT NULL, ##在book表中,bookid唯一。
`title` varchar(255) DEFAULT NULL,
`book_category_zh` varchar(25) DEFAULT NULL,
`book_category_en` varchar(10) DEFAULT NULL,
`max_chapter` varchar(255) DEFAULT NULL, ##该书的最大章节数,比如有20个章节,这个字段的值就是20
`author` varchar(50) NOT NULL DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8

表字段的说明,上边已有,wanbens的作用就是统计某一天有多少本书被用户完全阅读了,至少是阅读了最后一个章节。




应该说清楚了吧。
ACMAIN_CHM 2009-05-20
  • 打赏
  • 举报
回复

建议楼主能提供测试用的表和数据。然后说明正确结果。这样大家可以用你提供的表结构和数据来测试。以便减少理解上的差别和提高回答的准确。

WWWWA 2009-05-20
  • 打赏
  • 举报
回复
只有分段调试,显示变量值,看看问题出在哪里
码工码工 2009-05-20
  • 打赏
  • 举报
回复
谢谢,这几行,我也会写。
lacasadeco 2009-05-20
  • 打赏
  • 举报
回复
DELIMITER $$
create procedure wanbens(in d int, in m int ,in y int)
begin
END$$

DELIMITER ;

56,679

社区成员

发帖
与我相关
我的任务
社区描述
MySQL相关内容讨论专区
社区管理员
  • MySQL
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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