免责声明:我先在其他网站上发布此内容
我有一个大约200列宽的表(res_table)。其中一列名为“feature_lk”,它由一串数字“|”组成分隔。这些数字代表功能类别,它们位于另一个名为“features”的表中
感谢这个帖子:http://www.kirupa.com/forum/showthread.php?t=224203我想出了如何解析这些功能!
现在我的问题是如何查找它们?我觉得我需要加入我的两个表,但我不确定如何,或者我需要为我解析的每个功能执行另一个选择查询..这就是我所要做的(删除连接字符串)用于发布目的)
PHP Code:
<?php
$sql = ("SELECT * FROM res_table");
$result = mysql_query($sql);
while($row = mysql_fetch_array($result))
{
$feature_string = $row['features_lk'];
$features = explode( '|', $feature_string );
foreach( $features as $feature ) {
$feature = trim( $feature );
echo $feature.': ';
$sql2 = "SELECT * from features where features.feature_id like $feature";
$result2 = mysql_query($sql2);
while ($row2 = mysql_fetch_array($result2))
{
$feat_desc = $row2['feature_description']; //this is another column in the features table
echo $feat_desc . '<br>';
}
}
echo '<br>';
}
?>
这样可行,因为当我运行它时,我会得到看起来像这样的结果:
13: None
62: Water Softener - Rented
71: Full
168: Barn
222: Storage Shed
226: Walkout
309: Detached
347: 2 Story
384: Attic Storage
439: Laundry Hook Up
466: Rural
476: Trees
512: School Bus
562: Mud Room
563: Pantry
2273: Septic Tank
643: Private Well
我的问题是:有更好的方法吗?主res_table中大约有10k行,只有几百个命中,你可以看到执行的select语句的数量在任何时候都会大大增加。
我确定这是PHP + MySQL 101的东西,但我只是一个初学者,所以任何想法?提前谢谢。
答案 0 :(得分:2)
当您在列中存储多条信息时,表格不会被标准化。在feature_lk
上进行查找一定会很慢而且很困难。 feature_lk
应该成为自己的表格:
表feature_lk:
然后你的查询是:
SELECT f.* from features f
JOIN feature_lk lk ON (f.id=lk.feature_id)
JOIN res_table r ON (lk.res_table_id=r.id);
仅限一个查询。没有循环。没有解析出这些功能。
ETA
用任意字符
分割任意长度字符串的存储过程DELIMITER $$
DROP PROCEDURE IF EXISTS `dorepeat` $$
CREATE PROCEDURE `dorepeat`(in ToBeSplit LONGTEXT , in Splitter CHAR)
Begin
DECLARE TotalLength INT;
DECLARE SplitterPosition INT;
DECLARE SubstringLength INT;
DECLARE SubstringStart INT;
DROP Table if exists Split_Values;
CREATE temporary TABLE Split_Values (split varchar(255));
SET TotalLength = LENGTH(ToBeSplit);
SET SplitterPosition = LOCATE(Splitter, ToBeSplit);
SET SubstringStart = 1;
ss: WHILE SplitterPosition < TotalLength DO
IF SplitterPosition!=0 THEN
SET SubstringLength = SplitterPosition - SubstringStart;
Insert into Split_Values VALUES (SUBSTRING(ToBeSplit,SubstringStart,SubstringLength));
SET SubstringStart = SplitterPosition+1;
SET SplitterPosition = LOCATE(Splitter, ToBeSplit, SplitterPosition+1);
ELSE
Insert into Split_Values VALUES (SUBSTRING(ToBeSplit,SubstringStart));
SET SplitterPosition=TotalLength;
END IF;
END WHILE ss;
End $$
DELIMITER ;
在另一个过程中使用dorepeat
创建带有res_table_id和每个功能的临时表:
DELIMITER $$
DROP PROCEDURE IF EXISTS `multido` $$
CREATE PROCEDURE `multido`()
Begin
DECLARE done INT default 0;
DECLARE rt_id INT (10);
DECLARE features LONGTEXT;
DECLARE mycur cursor for select distinct res_table_id, feature_lk from res_table WHERE feature_lk!='';
DECLARE continue handler for sqlstate '02000' set done=1;
drop table if exists tmpfeatures;
create temporary table tmpfeatures( res_table_id int(10), feature varchar(255));
open mycur;
repeat
fetch mycur into rt_id,features;
call dorepeat(features,'|');
insert into tmpfeatures select rt_id, trim(split) from Split_Values;
until done end repeat;
close mycur;
End $$
DELIMITER ;
答案 1 :(得分:0)
你感觉到这里糟糕的数据库建模的痛苦。如果您对数据库模式有任何控制权,那么您应该对其进行修复,以便对其进行适当的规范化。无论何时,当您在数据库中看到管道(或逗号,制表符或其他任何)列表时,您都应该非常怀疑它。
您的表和类别之间应该有一个连接表,通常命名为RES_CATEGORIES,其中包含RES的ID和CATEGORIES的ID。这是在关系数据库中建模多对多关系的标准方法。
如果您无法控制架构,那么您最好的办法就是在代码中解析它并执行单独的查询(或查询)以获取类别信息。您至少可以在where子句中指定多个类别ID,以减轻其痛苦。
答案 2 :(得分:0)
根据我在你的问题中的理解,你需要一个中间表。例如,您有表tbl_user和tbl_features,其中用户可以订阅许多功能,并且每个功能都可以由许多用户订阅。
使用额外的表tbl_userfeatures {userFeatureID,userID,featureID}可以更好地管理您的数据库,该表链接其他两个表并允许您添加不同的组合。
答案 3 :(得分:0)
一个简单的优化步骤是在一步中获取功能,而不是在它们上面循环。像这样:
$result = mysql_query('SELECT * FROM res_table');
while ($row = mysql_fetch_array($result)) {
$features = str_replace('|', ',', $features);
$result2 = mysql_query("SELECT * FROM features WHERE feature_id IN $features");
while ($row2 = mysql_fetch_array($result2) {
printf('%d: %s', $row2['feature_id'], $row2['feature_description']);
}
}
这是res_table中每一行的一个查询,而不是每个功能的一行。
但在此之前,请先听取其他回复。如果您能够将数据库模式更改为更合理的模式,请执行此操作!