ON closer inspection the problem is solved if I remove the comment table join, but obviously this isn't ideal help appreciated!!
I'm trying to write a blog with Codeigniter. At the moment i'm displaying all the information that I want to display, but for some reason, when viewing the blog, I've got duplicate content for the categories. There are only 3 test categories in my database but 1 of my test posts that has all 3 selected is showing six and the other is showing just the one category twice.
Even stranger than that, the first blog post is also counting the wrong number of comments. It's displaying 6 when there are only 4 in the database and only two are related to that post, but the strangest of all is that the second post displays the correct number of comments, two. How can that be.
This is the query from the model in question.
$this->db->select('posts.id,
posts.title,
posts.slug,
posts.content,
posts.author,
posts.date,
posts.time,
posts.tags,
posts.status,
GROUP_CONCAT(categories.name SEPARATOR \'-\') AS categories,
count(comments.id) as total_comments
');
$this->db->group_by(array('posts.id'));
$this->db->join('posts_categories', 'posts_categories.blog_entry_id = posts.id', 'left outer', 'left outer');
$this->db->join('categories', 'posts_categories.blog_category_id = categories.category_id', 'left outer');
$this->db->join('comments', 'comments.post_id = posts.id', 'left outer' );
$query = $this->db->get('posts', $config['per_page'], $this->uri->segment(3));
The standard query generated is this:
SELECT DISTINCT `posts`.`id`,
`posts`.`title`, `posts`.`slug`,
`posts`.`content`, `posts`.`author`,
`posts`.`date`, `posts`.`time`,
`posts`.`tags`, `posts`.`status`,
GROUP_CONCAT(categories.name SEPARATOR '-') AS categories,
count(comments.id) as total_comments
FROM (`posts`)
LEFT OUTER JOIN `posts_categories` ON `posts_categories`.`blog_entry_id` = `posts`.`id`
LEFT JOIN `categories` ON `posts_categories`.`blog_category_id` = `categories`.`category_id`
LEFT JOIN `comments` ON `comments`.`post_id` = `posts`.`id`
GROUP BY `posts`.`id` LIMIT 1
The database dump can be found here
Any help would be greatly appreciated, this is making me crazy!
Cheers.
Do you have any qualms running another query to get the comment count? You can do the following query (assuming Active Record):
$this->db->where('parent_id', $post_id);
$this->db->count_all_results('comments');
This would have to be run for each post, though, so your # of queries would be n+1 where n = number of posts.
Related
I have two projects (A and B).
They're both built on CakePHP framework, and basically, they got the same structure, meaning that both their databases have the same structure. Let's say they are identical.
I have created a view, where I've put all the data needed to perform a search and I called it search_areas. Every column from the tables that are in the view are FULLTEXT indexes.
Now, when I perform a search on Project A, it works like a charm. But when I do it on project B, it takes forever. Actually, something jams, something in the code. The database works fine but the app is unusable for about 10 minutes. Has anybody encountered such a problem?
This is the sql that runs when a search is performed:
SELECT
Product.*,
MainImage.*,
Currency.rate,
Category.green_tax,
CategoriesCategory.full_alias,
(Product.price*Currency.rate + Category.green_tax)*1.24 as real_price,
MATCH (SearchArea.Cname,SearchArea.Mname,SearchArea.Pname,SearchArea.description,SearchArea.special_description,SearchArea.model,SearchArea.part_number,SearchArea.series,SearchArea.color,SearchArea.big_string) AGAINST ('+search term' IN BOOLEAN MODE) as score
FROM `products` AS `Product`
LEFT JOIN currencies AS `Currency` ON (`Product`.`currency` = `Currency`.`code`)
LEFT JOIN categories AS `Category` ON (`Product`.`category_id` = `Category`.`id`)
LEFT JOIN manufacturers AS `Manufacturer` ON (`Product`.`manufacturer_id` = `Manufacturer`.`id`)
LEFT JOIN categories_categories AS `CategoriesCategory` ON (`Product`.`category_id` = `CategoriesCategory`.`category_id`)
LEFT JOIN search_areas AS `SearchArea` ON (`SearchArea`.`id` = `Product`.`id`)
LEFT JOIN `product_images` AS `MainImage` ON (`MainImage`.`product_id` = `Product`.`id` AND `MainImage`.`main` = 1)
WHERE
MATCH (`SearchArea`.`Cname`,`SearchArea`.`Mname`,`SearchArea`.`Pname`,`SearchArea`.`description`,`SearchArea`.`special_description`,`SearchArea`.`model`,`SearchArea`.`part_number`,`SearchArea`.`series`,`SearchArea`.`color`,`SearchArea`.`big_string`) AGAINST ('+search term' IN BOOLEAN MODE)
AND `Product`.`active` = 1
LIMIT 15
Any ideas?
****** EDIT *****
I ran the query in mysql and it seems that there's the problem. It takes a very long time (2-5 minutes). Seems that I have to optimize my query, maybe find another solution. Thanks for helping. If anybody has an idea how to use the MATCH ... AGAINST ... syntax efficiently on a view or some concatenated element please post. I will probably abandon the above solution.
You are performing the filterings on a joined table 'SearchArea', no wonder it takes so long.
What your query does is, get all Products, join all the tables and then only keep what matches your filter. Your query should do the following, search SearchArea that have what your looking for and then only join the tables.
You should rewrite your query like so:
SELECT
Product.*,
MainImage.*,
Currency.rate,
Category.green_tax,
CategoriesCategory.full_alias,
(Product.price*Currency.rate + Category.green_tax)*1.24 as real_price,
MATCH (SearchArea.Cname,SearchArea.Mname,SearchArea.Pname,SearchArea.description,SearchArea.special_description,SearchArea.model,SearchArea.part_number,SearchArea.series,SearchArea.color,SearchArea.big_string) AGAINST ('+search term' IN BOOLEAN MODE) as score
FROM search_areas AS `SearchArea`
LEFT JOIN `products` AS `Product` ON (`SearchArea`.`id` = `Product`.`id`)
LEFT JOIN currencies AS `Currency` ON (`Product`.`currency` = `Currency`.`code`)
LEFT JOIN categories AS `Category` ON (`Product`.`category_id` = `Category`.`id`)
LEFT JOIN manufacturers AS `Manufacturer` ON (`Product`.`manufacturer_id` = `Manufacturer`.`id`)
LEFT JOIN categories_categories AS `CategoriesCategory` ON (`Product`.`category_id` = `CategoriesCategory`.`category_id`)
LEFT JOIN `product_images` AS `MainImage` ON (`MainImage`.`product_id` = `Product`.`id` AND `MainImage`.`main` = 1)
WHERE
MATCH (`SearchArea`.`Cname`,`SearchArea`.`Mname`,`SearchArea`.`Pname`,`SearchArea`.`description`,`SearchArea`.`special_description`,`SearchArea`.`model`,`SearchArea`.`part_number`,`SearchArea`.`series`,`SearchArea`.`color`,`SearchArea`.`big_string`) AGAINST ('+search term' IN BOOLEAN MODE)
AND `Product`.`active` = 1
LIMIT 15
On my website, I have a method that allows a logged in user to mark articles as a favourite, when logged in the articles are highlighted as being saved as a favourite, however if the user has no favourites, I cannot get the query to return any data, what is wrong with my query?
SELECT `job_id`,
COUNT(jobs.job_id) as jobs,
`employers`.`employer_id`,
`logo_small`, `logo_large`,
`company_name`, `job_tags`,
`favourite_employers`.`employer_id` AS employer
FROM (`employers`)
LEFT JOIN `jobs` ON `employers`.`employer_id` = `jobs`.`employer_id`
JOIN `favourite_employers` ON `favourite_employers`.`employer_id` = `jobs`.`employer_id`
WHERE `favourite_employers`.`user_id` = '2'
GROUP BY `jobs`.`employer_id`
ORDER BY `jobs`.`job_id` DESC
use LEFT JOIN instead of JOIN for the favourite_employers table
I know this may seem silly, but did you end the query with a ;?
It would be good to see the DB schema but you probably need a LEFT JOIN for favourite_employers.
The reason could be because this join:
JOIN `favourite_employers` ON `favourite_employers`.`employer_id` = `jobs`.`employer_id`
is returning nothing because there is no favorites
I'm trying to get all articles that are the current/latest articles in Mediawiki 1.16.0. I need to do this in phpMyadmin and make a dump from those results.
my SQL:
SELECT
page.page_title, page.page_latest
, revision.rev_id, revision.rev_text_id
, text.old_id, text.old_text
FROM page, revision, text
WHERE rev_id = page_latest AND rev_text_id = old_id
I get the image names also but not a problem. I feel that this SQL above is not getting the latest version of the articles.
If there is a way to not show image names and redirects in the results it would also help.
First of all please don't use that ugly implicit join syntax. It's confusing and error-prone.
Change it to this:
SELECT
page.page_title, page.page_latest
, revision.rev_id, revision.rev_text_id
, text.old_id, text.old_text
FROM page
INNER JOIN revision ON (rev_id = page_latest)
INNER JOIN text ON (rev_text_id = old_id)
Now you can see why: it's getting all pages. There is no where clause, there are just join clauses.
This is the DB layout: http://upload.wikimedia.org/wikipedia/commons/b/b7/MediaWiki_database_schema_1-17_%28r82044%29.png
And here are the description of the fields in the various tables:
http://www.mediawiki.org/wiki/Manual:Database_layout
Revised query
SELECT
p.page_title, p.page_latest
, MAX(revision.rev_id) as rev_id, revision.rev_text_id
, text.old_id, text.old_text
FROM page p
INNER JOIN revision r ON (r.rev_id = p.page_latest)
INNER JOIN `text` t ON (r.rev_text_id = t.old_id)
WHERE p.page_is_redirect = 0 AND p.page_namespace <> 6 /*NS_IMAGE = 6*/
GROUP BY p.page_latest
ORDER BY p.page_title
This filters out the redirects and excludes the pages where namespace = ns_image.
I'm not 100% sure though 'cause I don't have MediaWiki to test.
It's a bit difficult getting my problem into a short form, so I apologise if the title doesn't make sense.
Anyway, here is the problem:
$query = '
SELECT issues.*, comments.author AS commentauthor, favorites.userid AS favorited FROM issues
LEFT JOIN comments ON comments.issue = issues.id AND comments.when_posted = issues.when_updated
LEFT JOIN favorites ON favorites.ticketid = issues.id AND favorites.userid = \'' . $_SESSION['uid'] . '\'
' . $whereclause . '
ORDER BY issues.when_updated ' . $order;
Don't mind the fact that it's PHP as I am not asking for PHP help.
The query retrieves a bunch of issues, and what I'm wishing to do is obtain the row count of favorites that have favorites.ticketid matching issues.id. My use of LEFT JOIN favorites is not to get what I've just mentioned, but instead to obtain whether the client has favourited the issue, thus the part favorites.userid AS favorited.
I have tried doing the following: (all at once, I'm putting this in bulleted form for readibility)
duplicating the existing LEFT JOIN favorites and removing the user id check from the duplicate
adding , COUNT(favorites.ticketid) AS favoritescount to the SELECT section
adding AS favorited to the original LEFT JOIN as well as changing favorites.userid to favorited.userid
With that attempt, my query ends up returning only one row.
SELECT issues.*,
comments.author AS commentauthor,
favorites.userid AS favorited,
(
SELECT COUNT(favorites.id)
FROM favorites
WHERE ticketid = issues.id
) AS numfavorites
FROM issues
LEFT JOIN comments
ON comments.issue = issues.id
AND comments.when_posted = issues.when_updated
LEFT JOIN favorites
ON favorites.ticketid = issues.id
AND favorites.userid = ?uid
That should work, I'm just using a subquery to get number of favourites
This small SQL error is bugging me. It doesn't seem to be a problem with the query, just the scope(?), examples work best:
SELECT ocp.*, oc.*, GROUP_CONCAT( u.username SEPARATOR ', ') AS `memjoined`
FROM gangs_ocs_process ocp, gangs_ocs oc
LEFT JOIN users u ON u.userid IN ( ocp.membersin )
WHERE ocp.ocid =1 AND ocp.gangid =1 AND oc.oc_name = ocp.crimename
GROUP BY ocp.ocid
LIMIT 0 , 30
Theres a column (gangs_ocs_process.membersin) which has a list of IDs that have joined (ie 1,2,5). I'm trying to get the usernames for each of these IDs (from the users table) in one go.
The problem is LEFT JOIN users u ON u.userid IN ( ocp.membersin )
If I substitue 1,2,4 in for ocp.membersin (putting the literal list instead of column name), it works ok. It returns a column that has the usernames (image). However, if I leave in the ocp.membersin, I get this error:
#1054 - Unknown column 'ocp.membersin' in 'on clause'
This is the first time I've even used IN in left joins so I'm a bit lost.
Any help would be great :)
I don't think that "IN" will work for this syntax. MySQL expects IN to be something akin to a dataset, not a delimited string. I think you need to find a way to take membersin, expand it into a dataset MySQL can work with (maybe a temporary table), and join on that.
If you have delimited strings in your table, you have a design problem in your database. Add a new table to hold these values.
Are you sure 'membersin' is in the 'gangs_ocs_process' table, and not the 'gangs_ocs' table?
The reason you can't get it to work is because first you need to get your database NORMALIZED. You should NEVER, EVER have a list of ID's in a single column.
After taking another look, I think your problem is trying to aggregate at the wrong point as well as the IN syntax and that you should aggregate in a subquery restricted by the contents of the IN. I don't know enough about your schema to make this out of the box correct, but you want something like this. SomeKeyfield should relate back to gangs_ocs_process
SELECT ocp.*, oc.*, u.Memjoined
FROM gangs_ocs_process ocp, gangs_ocs oc
LEFT JOIN (Select SomeKeyField, GROUP_CONCAT( u.username SEPARATOR ', ') as memjoined
from users where userid in
(select membersin from gangs_ocs_process
where [whatever conditions] )
Group By SomeKeyField) u on ocp.SomeKeyField = u.SomeKeyField
WHERE ocp.ocid =1 AND ocp.gangid =1 AND oc.oc_name = ocp.crimename
GROUP BY ocp.ocid
LIMIT 0 , 30
This is a bad way to keep membership.
But if you still need to live with it, you may try REGEXP matching to test for membership:
SELECT ocp.*, oc.*, GROUP_CONCAT( u.username SEPARATOR ', ') AS `memjoined`
FROM gangs_ocs_process ocp
LEFT JOIN users u ON (ocp.membersin RLIKE CONCAT('(^|,)[[:blank:]]?', userid, '[[:blank:]]?($|,)'))
JOIN gangs_ocs oc ON (ocp.ocid = 1 AND ocp.gangid = 1 AND oc.oc_name = ocp.crimename)
GROUP BY ocp.ocid
LIMIT 0 , 30