【问题标题】:How to get nested Selects in a where_in clause in CodeIgniter's datamapper?如何在 CodeIgniter 的数据映射器的 where_in 子句中获得嵌套选择?
【发布时间】:2011-01-25 18:08:42
【问题描述】:

我有一个在 PhpMyAdmin/MySQL Workbench 中工作的 MySQL 查询。

SELECT *
FROM (`medfacts`)    
JOIN `categories_medfacts` ON `categories_medfacts`.`medfact_id` = `medfacts`.`id`    
where title in (    
 select medfacts.title from medfacts    
JOIN `categories_medfacts` ON `categories_medfacts`.`medfact_id` = `medfacts`.`id`    
 where categories_medfacts.category_id = 2    
)     
or title in (    
 select medfacts.title from medfacts    
JOIN `categories_medfacts` ON `categories_medfacts`.`medfact_id` = `medfacts`.`id`    
 where categories_medfacts.category_id = 3    
) 

(查询获取连接表 categories_medfacts 中列出的具有给定类别 ID 的所有 medfacts。)

我现在需要将它转移到我的 CodeIgniter 项目中,以允许我的程序根据需要添加尽可能多的 Have 子句。到目前为止,我所生成的查询大多是正确的。

function list_by_category($cat, $module) {
    /* Get a list of the Medfacts entries that have this category.         *
     */
    $this->db->join('categories_medfacts', 'categories_medfacts.medfact_id = medfacts.id');
    $this->where('medfacts.module_id', $module);
    /* If the category is an array, just get the articles that fall under all categories.
     * This shouldn't be more than a handful deep.
     */
    if (is_array($cat)) {
        foreach ($cat as $field => $value) {
            $this->where_in('title', "select medfacts.title from medfacts JOIN `categories_medfacts` ON `categories_medfacts`.`medfact_id` = `medfacts`.`id` where categories_medfacts.category_id = {$value}");
        }
    } else {
        $this->where('categories_medfacts.category_id', $cat);
    }
    $this->select('medfacts.title');
    return $this->get();
}

但是,我无法让它不逃避嵌套的 Select 语句,并最终得到以下结果:

SELECT `medfacts`.`title`
FROM (`medfacts`)
JOIN `categories_medfacts` ON `categories_medfacts`.`medfact_id` = `medfacts`.`id`
WHERE ( 
`medfacts`.`module_id` = '2'
AND `medfacts`.`title` IN ('select medfacts.title from medfacts JOIN `categories_medfacts` ON `categories_medfacts`.`medfact_id` = `medfacts`.`id` where categories_medfacts.category_id = 2') 
AND `medfacts`.`title` IN ('select medfacts.title from medfacts JOIN `categories_medfacts` ON `categories_medfacts`.`medfact_id` = `medfacts`.`id` where categories_medfacts.category_id = 3') 
 )
AND `medfacts`.`site_id` = 1  

注意 where in 子句中嵌套 select 周围的引号。

有没有办法让 Datamapper 不逃避嵌套选择?或者,有没有更好的方法来实现相同的目标?还是我坚持自己编写查询?

我在 PHP5 服务器上使用 CI 1.7.2 和 Datamapper DMZ 1.7.1(目前无法更新)。

编辑:我知道一个简单的or where 会返回匹配每个where 大小写的文章。然而,这不是我需要的。我只需要属于所有给定类别的结果。使用我当前的设置,or where 返回的结果太多(包括仅属于列出的类别之一的结果),而and where 不返回任何内容(也永远不会返回,因为 category_id 不能同时是“2”和“3”)。

另外,我发现了一个JOIN,如下面的也适用于MySQL,但我也不能将它翻译成CI(我没有发布它,因为我认为上面的where in是更清洁的方法) .

SELECT *    
FROM (`medfacts`)    
JOIN `categories_medfacts` ON `categories_medfacts`.`medfact_id` = `medfacts`.`id`    
join (    
    select medfacts.title, medfacts.id from medfacts    
JOIN `categories_medfacts` ON `categories_medfacts`.`medfact_id` = `medfacts`.`id`    
    where categories_medfacts.category_id = 2    
)  m1    
on m1.id = medfacts.id    
 join (    
    select medfacts.title, medfacts.id from medfacts    
JOIN `categories_medfacts` ON `categories_medfacts`.`medfact_id` = `medfacts`.`id`    
    where categories_medfacts.category_id = 3    
) m2    
on m2.id = medfacts.id    
where `medfacts`.`module_id` = '2'    
and medfacts.site_id = 1

【问题讨论】:

  • 哇!我还没有读过这个问题,但你正在做多个子查询并加入只是为了匹配多个类别 ID categories_medfacts.category_id?!我建议您询问如何优化该查询!
  • 也许您应该阅读这个问题,那么?我确实问过是否有更好的方法来达到同样的效果。
  • 这个查询会返回什么:SELECT * FROM medfacts,categories_medfacts WHERE categories_medfacts.medfact_id = medfacts.id AND categories_medfacts.category_id IN (2,3)
  • ifaour:记录太多。我只需要同时归类为 2 类和 3 类的记录,而不是 2 类或 3 类。您的查询获取匹配 2 类或 3 类的记录。

标签: php mysql codeigniter


【解决方案1】:

我发现只有一种方法可以在 CI 中执行子选择 - http://heybigname.com/2009/09/18/using-code-igniters-active-record-class-to-create-subqueries/

但是,前段时间,一位非常熟练的程序员(实际上是我的老板 :D)警告我,子选择非常慢,并且执行多个单独的选择或尝试进行连接(在可能的情况下)要快得多.. . 没有机会对其进行基准测试,所以把它当作一个小建议:)

【讨论】:

  • 如果有必要,我可以用完全不同的方式来做这件事,但我还没有想出更好的方法。我提出的初始查询使用了连接而不是 where...in,但 CI/DMZ 仍然不喜欢做我尝试过的事情。我会在你的链接的帮助下再试一次(谢谢你)。
  • 链接中提供的方法与该链接中所写的不同(我的子查询返回多个值),因此我对其进行了修改以尝试使用在 JOIN 中创建查询的方法.使用链接中的方法创建子查询,然后通过 JOIN 将其添加到工作中并获得所需的结果(它会生成我添加到问题中的 SQL)。不过,我不确定它的效率如何。
  • 试试 MySQL EXPLAIN 看看你的查询如何执行 - 如果你的索引设置正确并且选择时间没问题,你可能不需要进一步优化 - dev.mysql.com/doc/refman/5.0/en/explain.html
  • ... 另外,我建议使用慢查询日志并查看您的查询是否出现在那里(在您的本地服务器或生产服务器上 - 后者效率更高但您如果需要,仍然可以在本地模拟多个请求) - dev.mysql.com/doc/refman/5.0/en/slow-query-log.html
  • 让我重新表述一下 - 我不知道它与替代方法相比效率如何(假设有任何方法,除了 where...in 之外)。据我所知,考虑到所有因素,这种方法相当有效,但我们将看到何时将真实数据输入其中并查看它的扩展方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多