我會使用存儲過程,並從我的PHP代碼到MySQL進行一次調用。不幸的是MySQL是不是在處理數組類型PARAMS和犯規支持臺返回類型非常大,所以在存儲過程可能看起來有點醜:(
調用示例:
-- usage: call insert_question(<user_id>,<question>,<tags>,<separator>);
call insert_question(1,'why are stored procs useful ?', 'database,mysql,stored-procedures,kiss,performance',',');
$sql = sprintf("call insert_question(%d,'%s','%s','%s')", $userID,$ques,$tags,$separator);
輸出:
mysql> select * from tags order by tag_id;
+--------+-------------------+
| tag_id | tag |
+--------+-------------------+
| 1 | database |
| 2 | mysql |
| 3 | stored-procedures |
+--------+-------------------+
3 rows in set (0.00 sec)
mysql> select * from questions order by question_id;
Empty set (0.00 sec)
mysql> select * from question_tags order by tag_id, question_id;
Empty set (0.00 sec)
現在我們將調用存儲過程的:
call insert_question(1,'why are stored procs useful ?', 'database,mysql,stored-procedures,kiss,performance',',');
mysql> select * from tags order by tag_id;
+--------+-------------------+
| tag_id | tag |
+--------+-------------------+
| 1 | database |
| 2 | mysql |
| 3 | stored-procedures |
| 4 | kiss |
| 5 | performance |
+--------+-------------------+
5 rows in set (0.00 sec)
mysql> select * from questions order by question_id;
+-------------+---------+-------------------------------+---------------------+
| question_id | user_id | question | created_date |
+-------------+---------+-------------------------------+---------------------+
| 1 | 1 | why are stored procs useful ? | 2012-02-02 00:54:26 |
+-------------+---------+-------------------------------+---------------------+
1 row in set (0.00 sec)
mysql> select * from question_tags order by tag_id, question_id;
+--------+-------------+
| tag_id | question_id |
+--------+-------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 1 |
+--------+-------------+
5 rows in set (0.00 sec)
腳本:
完整的腳本在這裏:http://pastie.org/3299425
-- TABLES
drop table if exists users;
create table users
(
user_id int unsigned not null auto_increment primary key,
username varchar(32) unique not null
)
engine=innodb;
drop table if exists tags;
create table tags
(
tag_id smallint unsigned not null auto_increment primary key,
tag varchar(255) unique not null
)
engine=innodb;
drop table if exists questions;
create table questions
(
question_id int unsigned not null auto_increment primary key,
user_id int unsigned not null,
question varchar(512) not null,
created_date datetime not null
)
engine=innodb;
drop table if exists question_tags;
create table question_tags
(
tag_id smallint unsigned not null,
question_id int unsigned not null,
primary key (tag_id, question_id) -- clustered composite pk
)
engine=innodb;
-- PROCS
drop procedure if exists insert_question;
delimiter #
create procedure insert_question
(
in p_user_id int unsigned,
in p_question varchar(512),
in p_tags_csv mediumtext, -- comma separated plz
in p_separator char(1)
)
/*
usage:
call insert_question(1,'why are stored procs useful ?', 'database,mysql,stored-procedures,kiss,performance',',');
$sql = sprintf("call insert_question(%d,'%s','%s','%s)", $userID,$ques,$tags,$separator);
*/
proc_main:begin
declare v_question_id int unsigned default 0;
declare v_done tinyint unsigned default 0;
declare v_idx int unsigned default 1;
declare v_tag varchar(255) default null;
-- validate input params
if p_separator is null or length(p_separator) <= 0 then
set p_separator = ',';
end if;
if p_question is null or length(p_question) <= 0 then
leave proc_main;
end if;
if p_tags_csv is null or length(p_tags_csv) <= 0 then
leave proc_main;
end if;
-- split the tags into a memory table (ugly bit as mysql doesnt support table types)
drop temporary table if exists tmp_tags;
create temporary table tmp_tags(
tag_id smallint unsigned null,
tag varchar(255)
)engine = memory;
while not v_done do
set v_tag = trim(substring(p_tags_csv, v_idx,
if(locate(p_separator, p_tags_csv, v_idx) > 0,
locate(p_separator, p_tags_csv, v_idx) - v_idx, length(p_tags_csv))));
if length(v_tag) > 0 then
set v_idx = v_idx + length(v_tag) + 1;
insert into tmp_tags(tag) values(v_tag);
else
set v_done = 1;
end if;
end while;
-- which tags do we already have ?
update tmp_tags tt
inner join tags t on t.tag = tt.tag
set tt.tag_id = t.tag_id;
-- insert tags
insert into tags (tag) select tag from tmp_tags where tag_id is null;
update tmp_tags tt
inner join tags t on t.tag = tt.tag
set tt.tag_id = t.tag_id
where
tt.tag_id is null;
-- insert question and question_tags
insert into questions (user_id, question, created_date) values (p_user_id, p_question, now());
set v_question_id = last_insert_id();
insert into question_tags
select distinct tag_id, v_question_id from tmp_tags;
-- return output
select
p_question,
u.user_id,
u.username,
v_question_id,
tt.*
from
tmp_tags tt
inner join users u on u.user_id = p_user_id
order by
tt.tag_id;
-- cleanup
drop temporary table if exists tmp_tags;
end proc_main #
delimiter ;
-- TEST DATA
insert into users (username) values ('f00');
insert into tags (tag) values ('database'),('mysql'),('stored-procedures');
-- TESTING
select * from users order by user_id;
select * from tags order by tag_id;
select * from questions order by question_id;
select * from question_tags order by tag_id, question_id;
call insert_question(1,'why are stored procs useful ?', 'database,mysql,stored-procedures,kiss,performance',',');
select * from tags order by tag_id;
select * from questions order by question_id;
select * from question_tags order by tag_id, question_id;
希望這有助於:)
編輯:
OFC,在任何其他RDBMS(SQL服務器, oracle)sproc將是微不足道的:)
哇,好工作。也許這個系統有點過於複雜,但是任何額外的存儲過程暴露都是好事。許多系統似乎忽視它們,使得任何複雜的工作都變得困難。 – Aatch 2012-02-02 01:06:48
不幸的是,它使得這個服務器端解決方案變得複雜。例如,SQL服務器具有表格類型等,可以將sproc簡化爲幾個語句 - 但謝謝:) – 2012-02-02 01:14:06