开发者

Limit SQL join when using CodeIgniter active record class

开发者 https://www.devze.com 2023-03-08 08:45 出处:网络
I\'m getting a product listing. Each product 开发者_高级运维may have 1 or more image, I only want to return the first image.

I'm getting a product listing. Each product 开发者_高级运维may have 1 or more image, I only want to return the first image.

$this->db->select('p.product_id, p.product_name i.img_name, i.img_ext');    
$this->db->join('products_images i', 'i.product_id = p.product_id', 'left');
$query = $this->db->get('products p');

Is there anyway to limit the db->join to 1 record using the CI active record class?


Add $this->db->limit(1); before calling $this->db->get('products p');. See the docs at ellislab.com: search the page for limit.

EDIT: I misread the fact that you were trying to apply the LIMIT to the internal JOIN statement.

No. Since you can not do a LIMIT on an internal JOIN statement in regular SQL you can not do it with Code Igniter's ActiveRecord class.


You can achieve what you want using $this->db->group_by with a left join:

$this->db->select('products.id, products.product_name, products_images.img_name, products_images.img_ext');
$this->db->from('products');
$this->db->join('products_images', 'products_images.product_id = products.id', 'left');
$this->db->group_by('products.id'); 
$query = $this->db->get();

This should give you results by products.id (without repetition of products), with the first matching record from products_images joined to each result row. If there's no matching row from the joined table (i.e. if an image is missing) you'll get null values for the products_images fields but will still see a result from the products table.


To expand on @Femi's answer:

There's no good way to limit the JOIN, and, in fact, you don't really want to. Assuming both products_image.product_id and products.id have indexes (and they absolutely should if you're going to join against them repeatedly) when the database engine does a join, it uses the indexes to determine what rows it needs to fetch. Then the engine uses the results to determine where on the disk to find the records it needs. If you

You should be able to see the difference by running these SQL statements:

EXPLAIN 
SELECT p.product_id, p.product_name, i.img_name, i.img_ext
FROM products p
LEFT JOIN products_images i
    ON i.product_id = p.product_id

as opposed to:

EXPLAIN  
SELECT p.product_id, p.product_name, i.img_name, i.img_ext
FROM (SELECT product_id, product_name FROM products) p 
LEFT JOIN (SELECT img_name, img_ext FROM products_images) i
    ON i.product_id = p.product_id

The first query should have an index, the second one will not. There should be a performance difference if there's a significant number of rows the the DB.


Had this issue too the way I solved it was iterating over the results and removing the current object if the product_id had existed in a previous one. Create a array, push the product_id's to it while checking if they are repeats.

$product_array = array();
$i = 0;

foreach($result as $r){

    if(in_array($r->product_id,$product_array)){
        unset($result[$i]);
    }else{
        array_push($product_array,$r->product_id);
    }
    $i++;

} 

$result = array_values($result); //re-index result array

Now $result is what we want

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号