2

我目前正在开发一个内容管理系统,我想听听您对以下内容的看法:

我有一张桌子,page. 假设它看起来像这样

ID | Title | Content
1  | Test  | This is a test

除此之外,我还有一个page_option表(所以我可以存储与页面相关的选项,但我不希望有一个有限的选项列表 - 如果需要,模块可以将自己的选项添加到页面中。)

page_option表可能如下所示:

page_id | option_key  | option_value
1       | background  | red
1       | module1_key | chicken

现在要检索页面对象,我使用 Active Record 类执行以下操作(这是针对此问题的伪编码):

function get_by_id($page_id) {

 $this->db->where('id', $page_id);
 $page_object = $this->db->get('page');

 if($page_object->num_rows() > 0) {

   $page = $page_object->row();
   $this->db->where('page_id', $page_id);
   $options_object = $this->db->get('option');

   if($options_object->num_rows() > 0) {
     $page->options = $options_object->result();
   }

   return $page;

 }

 return $page_object->row();

}

我想知道的是,有没有办法在一个查询中执行此操作,以便选项键成为我选择中的虚拟列,所以我会得到:

ID | Title | Content        | background | module1_key
1  | Test  | This is a test | red        | chicken

在我的结果中,而不是对每一行进行单独的查询。如果有 10,000 个呢?等等。

提前谢谢了!

4

3 回答 3

1

使用 EAV(实体-属性-值)模型,您将始终需要处理此类问题。由于查询的复杂性,它们的效率也不是很高(大多数都需要旋转)。

SELECT page_id,
  MAX(CASE WHEN option_key = 'background' THEN option_value END) background,
  MAX(CASE WHEN option_key = 'module1_key' THEN option_value END) module1_key,
  MAX(CASE WHEN option_key = 'module2_key' THEN option_value END) module2_key
FROM page_option
GROUP BY page_id

例如,给定这张表:

| PAGE_ID |  OPTION_KEY | OPTION_VALUE |
|---------|-------------|--------------|
|       1 |  background |          red |
|       1 | module1_key |      chicken |
|       2 | module1_key |         duck |
|       3 | module1_key |          cow |
|       4 |  background |         blue |
|       4 | module2_key |        alien |
|       4 | module1_key |      chicken |

您将得到以下输出:

| PAGE_ID | BACKGROUND | MODULE1_KEY | MODULE2_KEY |
|---------|------------|-------------|-------------|
|       1 |        red |     chicken |      (null) |
|       2 |     (null) |        duck |      (null) |
|       3 |     (null) |         cow |      (null) |
|       4 |       blue |     chicken |       alien |

在这里拉小提琴。

然后只需加入page表格即可:) 我省略了该部分,以便将查询集中在分组本身中。

于 2013-10-22T20:10:15.257 回答
0

如果option_key是 uniqe per page_id(你没有两个或更多backgroundwith page_id==1)你可以这样做:

SELECT page.page_id, page.title, page.content,
  GROUP_CONCAT(option_key SEPARATOR '@') AS option_keys,
  GROUP_CONCAT(option_value SEPARATOR '@') as option_values,
FROM page
LEFT JOIN page_option ON page_option.page_id=page.page_id
WHERE page.page_id=USER_SPECIFIED_ID

您可以执行此 SQL 查询并将其结果放入$result. 在你应该做的每一项之后$result

$result[$i]["options"] = array_combine(
        explode("@",$result[$i]["option_keys"]),
        explode("@",$result[$i]["option_values"])
);

你可以用 a 来做,foreach也可以用array_walk

在这些之后,您有一个关联数组,其中包含以下选项$result[$i]["options"]

{
  "background" => "red",
  "module_key1"=> "chicken"
} 

我希望这是你想要的。

于 2013-10-22T19:42:37.160 回答
0

如果您可以使用 activerecord 类添加虚拟字段,您可以执行类似的操作:

 $this->db->add_field("(select group_concat(concat(option_key,':',option_value)  SEPARATOR ' ') from page_option where page_id=$page_id group by page_id)");

不会是最优的...

于 2013-10-22T18:08:53.170 回答