您好我有39个大型表,介于8,000到1,500,000行之间,用于在MySQL4中对数据进行分区。每张表代表一个原始机场代码,其中的数据是来自每个起源的包假期交易(140列)。
我正在为酒店名称制作一个自动建议字段,但我想根据包裹持续时间,包裹类型和来源进行调整。
我有另一张桌子,所有酒店只有3000行,所以我想使用这张表作为自动推荐功能,因为它的尺寸和速度都很小。
每家酒店都有很多起源,包装类型和包装时间。
我的问题是我应该如何填充所有来源的酒店表格。 到目前为止,我唯一的想法是每个包裹类型,包裹持续时间和机场代码的分隔列表。
示例记录:
hotel_name = Some Hotel
origin = YYC;YEG;YVR
duration = 04;05;06;07;09;10;14
package_Type = 03;04;09
然后使用:
SELECT `hotel_name` from `hotels`
WHERE `hotel_name` LIKE '%$typed_text%'
AND `package_duration` LIKE '%09%'
AND `package_type` LIKE '%04%'
AND `origin` LIKE '%YEG%'
ORDER BY `hotel_name`
这是解决此类查询的最佳方式吗?我还应该做些什么吗? 感谢
这绝不是推荐的方法,因为它几乎打破了数据库查询中的每个规则,但无论如何它都是
这是一个示例转储:
CREATE TABLE IF NOT EXISTS `hotels` (
`id` int(9) NOT NULL auto_increment,
`hotel_name` varchar(255) NOT NULL default '',
`origins` varchar(255) NOT NULL default '',
`package_types` varchar(255) NOT NULL default '',
`package_durations` varchar(255) NOT NULL default '',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
--
-- Dumping data for table `hotels`
--
INSERT INTO `hotels` (`id`, `hotel_name`, `origins`, `package_types`, `package_durations`) VALUES
(1, 'Bel Air Collection Resort & Spa Vallarta', 'YYC;YXX;YQQ;YEG;YLW;YUL;YQR;YYZ;YVR;YYJ;YWG;', '09;', '06;07;08;13;14;15;'),
(2, 'Grand Velas All Suites & Spa Resort, Riviera Maya', 'YYC;YXX;YQQ;YEG;YHM;YXU;YUL;YOW;YQB;YQR;YXE;YYZ;', '09;', '03;04;09;10;11;06;07;08;13;14;15;'),
(3, 'Barcelo Capella Beach Resort', 'YYC;YEG;YHZ;YUL;YOW;YYZ;YVR;YWG;', '09;', '06;07;08;13;14;15;'),
(4, 'Iberostar Cozumel', 'YYC;YBG;YYG;YEG;YFC;YHZ;YXU;YQM;YUL;YOW;YQB;', '09;', '06;07;08;13;14;15;'),
(5, 'Valentin Imperial Maya', 'YYC;YBG;YXX;YQQ;YEG;YHZ;YHM;YXU;YUL;', '09;', '06;07;08;03;04;09;10;11;13;14;15;');
查询表格的示例脚本:
$data[n] = 'resort'; //auto suggest text
$data[t] = '9'; //package_type
$data[d] = '7;8;10'; //durations
$data[o] = 'YUL;YVR'; //origins
//Split origins
foreach(explode(';',$data[o]) as $ori)
{
$origin_sql[] = "`origins` LIKE '%".str_pad(mysql_real_escape_string($ori), 2, "0", STR_PAD_LEFT).";%'";
}
$data[o] = "(".implode(' OR ',$origin_sql).")";
//Split durations
foreach(explode(';',$data[d]) as $dur)
{
$duration_sql[] = "`package_durations` LIKE '%".str_pad(mysql_real_escape_string($dur), 2, "0", STR_PAD_LEFT).";%'";
}
$data[d] = "(".implode(' OR ',$duration_sql).")";
if($data[n]!=''&&$data[o]!=''&&$data[t]!=''&&$data[d]!='')
{
$n = str_pad(mysql_real_escape_string($data[n]), 2, "0", STR_PAD_LEFT);
$t = str_pad(mysql_real_escape_string($data[t]), 2, "0", STR_PAD_LEFT);
$s = "SELECT `hotel_name` FROM `backend_hotels` WHERE
`hotel_name` LIKE '%".$n."%' AND
`package_types` LIKE '%".$t.";%' AND
".$data[o]." AND
".$data[d]."
ORDER BY `hotel_name` ASC;";
if($q = mysql_query($s))
{
while($r=mysql_fetch_array($q,MYSQL_ASSOC))
{
$names[] = $r[hotel_name];
}
echo json_encode($names);
}
}
生成如下查询:
SELECT `hotel_name`
FROM `hotels`
WHERE `hotel_name` LIKE '%resort%'
AND `package_types` LIKE '%09;%'
AND (
`origins` LIKE '%YUL;%'
OR `origins` LIKE '%YVR;%'
)
AND (
`package_durations` LIKE '%07;%'
OR `package_durations` LIKE '%08;%'
OR `package_durations` LIKE '%10;%'
)
ORDER BY `hotel_name` ASC
LIMIT 0 , 30
就像我提到的那样,由于LIKE查询速度慢,这种方法对大型数据集来说并不好。这恰好更容易实现1100万套餐和3000家酒店,我只想展示我最终实施的内容,以防它可以帮助其他任何人
答案 0 :(得分:3)
我通常做的是将关系分解为部分:
每个酒店都有起源,包类型和包裹持续时间。
所以你有:
现在,如果你想到它,酒店是这里的主要主题,因此它应该是标记的项目(想象一下facebook)
现在,你如何“标记”?让我们来源吧。每个酒店都可以有很多起源,起源可能有很多酒店。你现在做的是建立一个“联结表”。我会尝试在这里画画:
Hotels Hotels_Origin Origin
1. Marriott 1-1 1. US
2. Waterfront 1-2 2. UAE
2-1
你看到“标签”只不过是一个基于交叉点的“关系”。在此示例中,万豪标记在两个位置,Waterfront标记为美国。要获得此查询,您必须使用“LEFT JOIN”
LEFT JOIN关键字返回左表(table_name1)中的所有行,即使右表(table_name2)中没有匹配项也是如此。 ( W3schools ) - 这只是一个解释。
左连接确保我们根据参数的左侧获得我们想要的东西:
SELECT hotels.name, origin.name FROM hotels
LEFT JOIN hotels_origin ON hotels.id = hotels_origin.id //match the hotel to junction
LEFT JOIN hotels_origin ON hotels_origin.id = origin.id //match junction to origins
WHERE hotel.id=1 //get hoted by id
以下返回ID为1(万豪)的酒店:
hotels.name origin.name
Marriott US
Marriott UAE
现在说,你对所有其他表做同样的事情。
这种方法的优点是
表格中没有重复项。您可以将一个来源标记为许多酒店,只修改了联结表关系。
此方法具有更高的可扩展性和可维护性
更容易查找,尤其是自动建议(因为没有重复)
你不修改记录,只修改关系。
现在的问题是......您需要重新构建数据库。
答案 1 :(得分:1)
不,这不是最好的方法。您不希望在列中使用分隔列表。你想要的是一个表示每个关系的联结表。您想以第三范式设计数据库。
在上面的示例中,您需要将每个多对多关系分解为自己的表。因此酒店表将有一个主键(id),名称等。然后有一个HotelToOrigin表,每行持有一个hotel_id和origin_id。然后,HotelToDuration表类似,hotel_id和duration_id。等等。设置起来有点复杂,但这使得查询数据库变得最简单,最准确。如果您使用上面提到的表结构的LIKE语句,如果您的包类型为'044',您将在查询中得到它而不仅仅是'04'。所以你的查询将是不准确的。