奇怪的是,我用mySQL做了很多开发,今天遇到的一些事情从来没有遇到过。
所以,我有一个 user_items 表
ID | name
---------
1 | test
然后我有一个 item_data 表
ID | item | added | info
-------------------------
1 | test | 12345 | important info
2 | test | 23456 | more recent important info
然后我有一个电子邮件表
ID | added | email
1 | 12345 | old@b.com
2 | 23456 | a@b.com
3 | 23456 | b@c.com
和一个 emails_verified 表
ID | email
-----------
1 | a@b.com
现在我很欣赏这些表的设置可能效率不高,但这不能改变,而且比看起来要复杂得多。
我想要做的如下。我希望能够搜索用户项目并显示相关信息,以及相关的任何电子邮件,以及显示电子邮件是否已通过验证。
user_items.name = item_data.item
item_data.added = emails.added
emails.email = emails_verified.email
因此,对于用户项目 1,进行测试。我希望能够返回其 ID、名称、最新信息、最新电子邮件及其验证状态。
所以我想回来
ID => 1
name => test
information => more recent important info
emails => array('0' => array('email' => 'a@b.com' , 'verified' => 'YES'),'1' => array('email' => 'b@c.com' , 'verified' => 'NO'))
现在我可以相对轻松地使用多个查询来做到这一点。然而,我的研究表明,与使用一个(尽管非常复杂)带有大量连接语句的 mysql 查询相比,这要耗费更多的资源/时间。
使用一个查询的原因也将是有用的(我相信)是因为我可以相对容易地添加搜索功能 - 添加到查询复杂的 where 语句。
为了使事情更复杂,我正在使用 CodeIgniter。我不能太挑剔:) 所以任何无 CI 答案仍然非常有用。
到目前为止我得到的代码如下。然而,“我不太确定我在做什么”。
function test_search()
{
$this->load->database();
$this->db->select('user_items.*,item_data.*');
$this->db->select('GROUP_CONCAT( emails.email SEPARATOR "," ) AS emails', FALSE);
$this->db->select('GROUP_CONCAT( IF(emailed.email,"YES","NO") SEPARATOR "," ) AS emailed', FALSE);
$this->db->where('user_items.name','test');
$this->db->join('item_data','user_items.name = item_data.name','LEFT');
$this->db->join('emails','item_data.added = emails.added','LEFT');
$this->db->join('emailed','emails.email = emailed.email','LEFT');
$this->db->group_by('user_items.name');
$res = $this->db->get('user_items');
print_r($res->result_array());
}
对此的任何帮助将不胜感激。
这真的是复杂的 sql - 这真的是实现此功能的最佳方式吗?
谢谢
更新
继 Cryode 的出色回答之后。
唯一的问题是它只返回一封电子邮件。但是,通过使用 GROUP_CONCAT,我能够将所有电子邮件和所有 email_verified 状态转换为一个字符串,然后我可以使用 PHP 进行分解。
为了澄清是子查询,
SELECT item, MAX(added) AS added
FROM item_data
GROUP BY item
本质上是创建一个临时表?
与此处概述的类似
当然,子查询是必要的,以确保您只从 item_data 获得一行 - 最近的一行?
最后回答有关设计不佳的数据库的注释。
数据库是这样设计的,因为 item_data 会定期更改,但我们希望保留历史记录。
电子邮件是项目数据的一部分,但因为可以有任意数量的电子邮件,并且我们希望它们是可搜索的,所以我们选择了一个单独的表格。否则,电子邮件必须在 item_data 表中进行序列化。
emails_verified 表是独立的,因为一封电子邮件可以与多个项目相关联。
鉴于此,尽管(显然)查询很复杂,但它似乎仍然是一个合适的设置..?
谢谢
最后更新
Cryodes 答案通常是与数据库架构相关的非常有用的答案。
稍微概念化一下,如果我们将版本 ID 存储在 user_items 中,我们就不需要子查询。
因为版本之间的数据不一定一致,所以我们将废弃他的建议项目表(对于这种情况)。然后我们可以从 item_data 表中获取正确的版本我们还可以根据版本 id 获取 items_version_emails 行,并从我们的“电子邮件”表中获取相应的电子邮件。
IE 完美运行。
这样做的缺点是,当我在 item_data 中添加新版本数据时,我必须使用已插入的新版本更新 user_items 表。
这很好,但作为一个概括点,什么更快?我认为建议这种设置的原因是它更快 - 每次添加新数据时进行额外的更新是值得的,以在显示大量行时保存潜在的数百个子查询。尤其是考虑到我们显示的数据多于更新数据。
只是为了了解在未来设计数据库架构时是否有人有任何链接/一般指导,说明什么更快以及为什么这样我们都可以制作更好的优化数据库。
再次感谢 Cryode !!