我有2张桌子。表1是“文章”,表2是“article_categories”。当用户创建文章时,它将存储在“文章”中。用户在创建文章时可以选择显示本文的各种类别。目前,可以选择一篇文章属于10-25个类别的任何地方(将来可能会增加)。提交文章的这些类别存储在“article_categories”中。因此,这意味着单个文章ID可以在表'article_categories'中具有多个相关值。从两个表中检索所有值时,我需要提取“article_categories”中的所有值,并将值存储在数组中。
我的问题是要使用什么SQL查询才能这样做?我应该使用内连接,左连接,外连接......?最好的方法是什么?我确实在phpmyadmin中尝试了一些这些连接,并且它们给了我相同文章的重复值,实际上,文章应该只被提取一次并且所有相关的类别都要被提取。我想在同一个查询中完成所有操作,而不必将查询拆分为2个不同的以完成此操作。我正在附加我的表格结构,以便您轻松:
CREATE TABLE IF NOT EXISTS `articles` (
`article_id` int(11) unsigned NOT NULL auto_increment,
`creator_id` int(11) unsigned NOT NULL,
`article_title` varchar(150) NOT NULL,
`article_status` varchar(10) NOT NULL,
PRIMARY KEY (`article_id`),
KEY `buyer_id` (`creator_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
--
-- Dumping data for table `articles`
--
INSERT INTO `articles` (`article_id`, `creator_id`, `article_title`, `article_status`) VALUES
(1, 1, 'My article 1', 'Pending');
CREATE TABLE IF NOT EXISTS `article_categories` (
`article_id` int(11) unsigned NOT NULL,
`category_id` smallint(3) unsigned NOT NULL,
PRIMARY KEY (`article_id`,`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Dumping data for table `article_categories`
--
INSERT INTO `article_categories` (`article_id`, `category_id`) VALUES
(1, 1),
(1, 2),
(1, 3),
(1, 4),
(1, 5),
(1, 36),
(1, 71);
另请注意,我在article_categories表中的article_id和category_id键上有一个复合键。我使用的示例查询如下:
SELECT *
FROM articles, article_categories
WHERE articles.article_id = article_categories.article_id
AND articles.article_id = 1;
这导致:
article_id creator_id article_title article_status article_id category_id
1 1 My article 1 Pending 1 1
1 1 My article 1 Pending 1 2
1 1 My article 1 Pending 1 3
1 1 My article 1 Pending 1 4
1 1 My article 1 Pending 1 5
1 1 My article 1 Pending 1 36
1 1 My article 1 Pending 1 71
可以看出,articles表中的值是重复的,它也能够获取所有类别(如果格式化了,它就是最后一列)。我只想从articles表中获取一次值并在循环中获取category_id,这样我就可以在数组中添加这些循环值并继续进行处理。这是我从上面获取值后打算做的事情:
<?php
//i wanted to check if the article_id exists before i pull the related categories.
//If I do it this way and output using mysql_num_rows, it gives me value 7,
//when in fact, the there's only 1 article with such Id. This means it also counts
// the number of categories. Is there a way to uniquely identify only the number of
// articles (just to see if it exists or not, in the place)
$result = mysql_query("SELECT *
FROM articles, article_categories
WHERE articles.article_id = article_categories.article_id
AND articles.article_id = 1");
while ( $rows = mysql_fetch_array($result) )
{ //i don't think this the following 2 assignments should be done in the loop
$article_id = $rows['article_id'];
$article_title = $rows['article_title'];
//(loop all the category_id from the 2nd table and add to the array below)
$categories_id[] .= ??????? --> How do i do this?
}
?>
显然,我不能在上面做LIMIT 1因为这会限制我检索所有类别ID的能力。
所以我的问题是如何从第二个表中获取所有category_id(在循环中)并将它们添加到数组中,同时确保表1中的值只被提取一次(I确实意识到从表1中获取的值是相同的,但循环它们没有意义)。为了实现这一点,我想了解我应该使用什么样的Join以最高效率执行查询并使用最少的资源,所有这些都在一个查询中以最小化数据库上的命中。我希望有道理。
提前致谢。
答案 0 :(得分:3)
修改强>:
SELECT articles.article_id, articles.article_title, GROUP_CONCAT(article_categories.category_id SEPARATOR ',') as category_id
FROM articles
LEFT JOIN article_categories ON (articles.article_id = article_categories.article_id)
-- WHERE CLAUSE IF YOU WANT/NEED --
GROUP BY articles.article_id;
修改强>:
为组concat GROUP_CONCAT(article_categories.category_id SEPARATOR ',') as category_id
<?php
$result = mysql_query("SELECT articles.article_id, articles.article_title, GROUP_CONCAT(article_categories.category_id SEPARATOR ',') as category_id
FROM articles, article_categories
WHERE articles.article_id = 1
GROUP BY articles.article_id;");
while ( $rows = mysql_fetch_array($result) )
{
$article_id = $rows['article_id'];
$article_title = $rows['article_title'];
//(loop all the category_id from the 2nd table and add to the array below)
$categories_id = explode(',', $rows['category_id']);
}
?>
请注意群组连续,因为它确实有限制:
结果被截断为最大长度由。给出
group_concat_max_len
系统 变量,其默认值为1024
。值可以设置得更高, 虽然有效最大长度 返回值的约束受到约束max_allowed_packet
的价值。
修改强>: 也没有使用组concat我会继续按照你的方式进行...只需使类别ID成为你的主要循环结构:
<?php
$result = mysql_query("SELECT articles.article_id, articles.article_title, article_categories.category_id
FROM articles, article_categories
WHERE articles.article_id = 1");
$articles = array();
while ( $rows = mysql_fetch_array($result) )
{
if(!array_key_exists($rows['article_id'], $articles)
{
$articles[$rows['article_id']] = array(
'article_id' => $rows['article_id'],
'article_title' => $rows['article_title']
'categories_id' => array()
);
}
$articles[$rows['article_id']][] = $rows['categories_id'];
}
?>
这样你只需要查询一次,然后你就必须遍历文章以对文章的数据进行操作。
答案 1 :(得分:0)
在您描述的多对多场景中,您无法避免在任何单个结果集中出现重复数据。
这是一个想法。执行单独的查询以构建类别名称数组,并将其数据库键作为数组索引。
$sql = "SELECT category_id, category_name FROM Categories";
$result = mysql_query($sql);
$arrCategories = array();
while ( $row = mysql_fetch_assoc($result) {
$arrCategories[$row['category_id']] = $row['category_name'];
}
现在,您拥有数组中所有类别的名称。
当您选择文章时,您必须执行单独的查询,从连接表中提取其category_ids。您可以使用二维数组来获取文章ID列表及其关联类别
$arrArticleCategoryIds = array();
$result = mysql_query("SELECT *
FROM articles, article_categories
WHERE articles.article_id = article_categories.article_id
AND articles.article_id = 1");
while ( $rows = mysql_fetch_array($result) )
{
// why bother doing this when you've already hard-coded "1"?
$article_id = $rows['article_id'];
$article_title = $rows['article_title'];
//(loop all the category_id from the 2nd table and add to the array below)
// $categories_id[] .= ??????? --> How do i do this?
// here's how:
$sql = "SELECT category_id
FROM `article_categories`
WHERE article_id = $article_id
";
$category_id_results = mysql_query($sql);
while ( $category_id_row = mysql_fetch_assoc($category_id_results) ) {
$arrArticleCategoryIds[$article_id][] = $row['category_id'];
}
}
你最终会得到两个阵列:
$arrCategories
Array
(
[1] => apple
[2] => banana
...
)
$arrArticleCategoryIds
Array
(
[1] => Array
(
[1] => 13
[2] => 9
)
[3] => Array
(
[1] => 5
[2] => 7
)
)
)
其中'1'和'3'是文章ID,而13,9,5和7是属于他们在其下找到的文章ID的类别ID。