2011-08-14 2 views
0

이 저장 프로 시저를 사용하는 것이 좋습니다. 누군가 내 실수를 설명 할 수 있기를 기대하면서 전체 덤프를 게시합니다.동적보기가있는 저장 프로 시저가 필드 수를 새로 고치지 않습니다.

drop table if exists questions; 

create table questions (
id int not null auto_increment primary key, 
description varchar(200) 
) engine = myisam; 

insert into questions (description) 
values 
('Question 1'), 
('Question 2'), 
('Question 3'); 

drop table if exists answers; 

create table answers (
id int not null auto_increment primary key, 
question_id int, 
description varchar(10) 
) engine = myisam; 

insert into answers (question_id,description) 
values 
(1,'no'), 
(1,'no'), 
(1,'yes'), 
(1,'no'), 
(1,'yes'), 
(2,'no'), 
(2,'yes'), 
(2,'yes'), 
(2,'yes'), 
(2,'no'), 
(2,'no'), 
(2,'no'), 
(2,'yes'), 
(2,'no'), 
(3,'no'), 
(3,'no'), 
(3,'no'), 
(3,'yes'); 

이 내 저장 프로 시저입니다 :

delimiter // 
drop procedure if exists dynamic_view // 
create procedure dynamic_view() 
begin 
declare cnt int default 0; 
declare finito int default 0; 
declare qid int; 
declare qdescription varchar(100); 
declare qanswer varchar(100); 
declare i int default 1; 
declare j int; 
declare str varchar(20000) default ''; 
declare str2 varchar(20000); 
declare str3 varchar(20000); 
declare curs1 cursor for select id,description from questions order by id; 
declare curs2 cursor for select description from answers where question_id = qid; 
declare continue handler for not found set finito = 1; 
-- drop table if exists tmp; 
select count(*) as num into @cnt from answers group by question_id order by num desc limit 1; 
drop table if exists tmp; 
while i <= @cnt do 
    set str = concat(str,'answer',i,' varchar(10),'); 
    set i = i + 1; 
end while; 
set str = substr(str,1,char_length(str)-1); 
set @str = concat('create temporary table tmp (id int,question varchar(200),',str,');'); 
prepare stmt from @str; 
execute stmt; 
deallocate prepare stmt; 
open curs1; 
mio_loop:loop 
fetch curs1 into qid,qdescription; 
if finito = 1 then 
close curs1; 
leave mio_loop; 
end if; 
open curs2; 
set str2 = 'insert into tmp (id,question,'; 
set j = 1; 
set str3 = ''; 
mio_loop2:loop 
fetch curs2 into qanswer; 
if finito = 1 then set finito = 0; 
    close curs2; 
    leave mio_loop2; 
end if; 
set str2 = concat(str2,'answer',j,','); 
set str3 = concat(str3,"'",qanswer,"',"); 
set j = j + 1; 
end loop mio_loop2; 
set str2 = substr(str2,1,char_length(str2)-1); 
set str3 = substr(str3,1,char_length(str3)-1); 
set @str2 = concat(str2,') values (',qid,",'",qdescription,"',",str3,');'); 
prepare stmt from @str2; 
execute stmt; 
deallocate prepare stmt; 
end loop mio_loop; 
select * from tmp; 
end; // 
delimiter ; 

을하고 내가 그것을 호출 할 때 나는이 출력

mysql> call dynamic_view(); 
+------+------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ 
| id | question | answer1 | answer2 | answer3 | answer4 | answer5 | answer6 | answer7 | answer8 | answer9 | 
+------+------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ 
| 1 | Question 1 | no  | no  | yes  | no  | yes  | NULL | NULL | NULL | NULL | 
| 2 | Question 2 | no  | yes  | yes  | yes  | no  | no  | no  | yes  | no  | 
| 3 | Question 3 | no  | no  | no  | yes  | NULL | NULL | NULL | NULL | NULL | 
+------+------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ 
3 rows in set (0.23 sec) 
이제

의 난 = 2 question_id 한 기록을 삭제하는 것이 가정하자를 얻을. 최대 레코드 수가 9 인 ID입니다. 삭제하면 레코드가 8이되므로 마지막 열이 사라져야합니다. 내가 다시 저장 프로 시저의 전체 코드를 실행하는 경우, 그러나

Error Code : 1054 
Unknown column 'pivot.tmp.answer9' in 'field list' 

후 나는 내가 올바른 결과를 얻을 리콜 : 내 SP를 호출하면

delete from answers where id = 14; 

나는이 오류가

mysql> call dynamic_view(); 
+------+------------+---------+---------+---------+---------+---------+---------+---------+---------+ 
| id | question | answer1 | answer2 | answer3 | answer4 | answer5 | answer6 | answer7 | answer8 | 
+------+------------+---------+---------+---------+---------+---------+---------+---------+---------+ 
| 1 | Question 1 | no  | no  | yes  | no  | yes  | NULL | NULL | NULL | 
| 2 | Question 2 | no  | yes  | yes  | yes  | no  | no  | no  | yes  | 
| 3 | Question 3 | no  | no  | no  | yes  | NULL | NULL | NULL | NULL | 
+------+------------+---------+---------+---------+---------+---------+---------+---------+---------+ 
3 rows in set (0.19 sec) 

임시 테이블을 삭제 한 이유를 이해할 수 없습니다. 미리 감사드립니다. 편집하십시오. 현상금을 시작하고 싶었지만 버튼을 찾지 못했습니다. :)

저는 2 일 후에 만 ​​현상금을 시작할 수 있다는 메타를 읽었습니다. 절대로 언급하지 않았습니다. 누군가가 나를 도울 수 있기를 바랍니다 :)

+0

은 시저의 끝에서 TMP를 포기하려고? –

+0

안녕하세요. 지금 당장 시도했다. 아무것도 바뀌지 않습니다. –

+0

임시 테이블을 제대로 삭제할 수 없다고 생각됩니다. (연결을 끝내지 않고 자동으로 삭제하지 않고) tmp1, tmp2, tmp3과 같은 임시 테이블 이름을 사용하여 다른 임시 테이블을 만들어 다음 테이블의 이름을 추적하는 것이 좋습니다. 또한 필요할 때 저장 프로 시저가 재진입 될 수 있습니다. –

답변

1

한번 비슷한 질문을 보았습니다. 이 링크를 봐 - unable to add columns dynamically to table using alter

닉, 나는 임시 테이블에서 데이터를 출력 준비 문을 사용하는 것이 좋습니다 (...이 테이블은 SP에 준비된 진술로 만들어졌으며 이것은 버그처럼 보입니다 - SELECT * inside PROCEDURE gives "Unknown column" on second loop if tbl changed). 이 코드

select * from tmp'; 

- -

그냥 마지막 줄을 변경

PREPARE stmt FROM 'select * from tmp'; 
EXECUTE stmt; 
DEALLOCATE PREPARE stmt; 
+0

당신은 내 영웅입니다. 나는 당신의 대답 없이는 결코 풀리지 않았을 것입니다. 각 행의 출력을 말하기 위해 커서에 제한 x, 1을 사용하여 긴 디버그를 만들었으므로이 오류의 원인을 찾을 수 없었습니다. 고맙습니다. 좋은 대답. 너 규칙 : –

+0

팝업은 너에게 현상금을주기 위해 3 시간을 기다려야한다고 말해 준다. 당신은 그것을 얻을거야 :) –

+0

Howerver 그것은 몇 가지 버그가 많은 년 후에 지속 슬프다. : –

관련 문제