Related
I'm trying to improve a live product search for the admin side of our online store.
We're currently using the following query:
SELECT p.product_id, p.full_title, p.descript, p.cost, p.no_vat, p.high_pic, p.prod_type, count(p.product_id) AS occurence, t.descript AS type_desc, p.available
FROM gdd_product as p, gdd_prodtype as t, gdd_info as i
LEFT JOIN gdd_keyword as k ON i.product_id = k.product
WHERE p.prod_type = t.prod_type
AND i.product_id = p.product_id
AND replace(concat_ws(p.descript, i.info_search1, i.info_search2, i.info_search3, k.keyword),' ','')
LIKE '%tool%'
GROUP BY p.product_id
ORDER BY occurence DESC, cost ASC LIMIT 30
This works, but omits any results which don't have an entry in the info_search columns.
So I tried changing it so that gdd_info is LEFT JOINed, with this code:
SELECT p.product_id, p.full_title, p.descript, p.cost, p.no_vat, p.high_pic, p.prod_type,
count(p.product_id) AS occurence, t.descript AS type_desc, p.available
FROM gdd_product as p, gdd_prodtype AS t
LEFT JOIN gdd_info as i ON p.product_id = i.product_id
LEFT JOIN gdd_keyword as k ON p.product_id = k.product
WHERE p.prod_type = t.prod_type
AND replace(CONCAT_WS(p.descript, i.info_search1, i.info_search2, i.info_search3, k.keyword),' ','')
LIKE '%tool%'
GROUP BY p.product_id
ORDER BY occurence DESC, cost ASC
LIMIT 30
...but that throws an error:
SQL Error (1054): Unknown column 'p.product_id' in 'on clause'
What am I doing wrong?
1st. Don't mix standards the ANSI standards (ANSI-92 vs ANSI-89). Either use INNER/CROSS/LEFT join or the , notation but not both. It's bad form and may eventually break; and maybe what's causing your p.product error now.
SELECT p.product_id, p.full_title, p.descript, p.cost
, p.no_vat, p.high_pic, p.prod_type
, count(p.product_id) AS occurence, t.descript AS type_desc
, p.available
FROM gdd_product as p
INNER JOIN gdd_prodtype AS t
on p.prod_type = t.prod_type
LEFT JOIN gdd_info as i
ON p.product_id = i.product_id
LEFT JOIN gdd_keyword as k
ON p.product_id = k.product
WHERE replace(CONCAT_WS(p.descript, i.info_search1, i.info_search2, i.info_search3, k.keyword),' ','')
LIKE '%tool%'
GROUP BY p.product_id
ORDER BY occurence DESC, cost ASC
LIMIT 30
2nd. the reason why it's omitting records is likely because NULL concatenated with a string is NULL. Then you search for a string against a null which will never return a result. You need to coalesce the i.info_search1... with a empty set '' coalesce(i.info_earch1,'') and so on... so it takes the 1st non-null value in a series and then a string is compared against a string
replace(CONCAT_WS(
coalesce(p.descript,'')
, coalesce(i.info_search1,'')
, coalesce(i.info_search2,'')
, coalesce(i.info_search3,'')
, coalesce(k.keyword,'')),' ','')
Giving us...
SELECT p.product_id, p.full_title, p.descript
, p.cost, p.no_vat, p.high_pic, p.prod_type
, count(p.product_id) AS occurence, t.descript AS type_desc
, p.available
FROM gdd_product as p
INNER JOIN gdd_prodtype AS t
on p.prod_type = t.prod_type
LEFT JOIN gdd_info as i
ON p.product_id = i.product_id
LEFT JOIN gdd_keyword as k
ON p.product_id = k.product
WHERE replace(CONCAT_WS(
coalesce(p.descript,'')
, coalesce(i.info_search1,'')
, coalesce(i.info_search2,'')
, coalesce(i.info_search3,'')
, coalesce(k.keyword,'')),' ','')
LIKE '%tool%'
GROUP BY p.product_id
ORDER BY occurence DESC, cost ASC
LIMIT 30
Think of it this way...
Say p.descript exists but info doesn't on your left join... so you concat p.descript with null getting null. Nothing will be like null so you get no records as you can't execute an equality check (like) on a null value and expect to get a result.
Now say p.descript doesn't exist and is null, concat it with anything that is null is yet again null so you have the same result.
Since any value could be null in your concat_WS string we need to coalesce all values just in case.
and now we have a valid string compared against your like and thus when your string matches your like, you'll now get results instead of when a column value in your ws_concat being null wiping your record out.
I run this query to get 20 random items from my wordpress database based on things like rating, category, etc
SELECT (A.user_votes/A.user_voters) as site_rating, B.ID as post_id, B.post_author, B.post_date,E.name as category
FROM `wp_gdsr_data_article` as A
INNER JOIN `wp_posts` as B ON (A.post_id = B.id)
INNER JOIN wp_term_relationships C ON (B.ID = C.object_id)
INNER JOIN wp_term_taxonomy D ON (C.term_taxonomy_id = D.term_taxonomy_id)
INNER JOIN wp_terms E ON (D.term_id = E.term_id)
WHERE
B.post_type = 'post' AND
B.post_status = 'publish' AND
D.taxonomy='category' AND
E.name NOT IN ('Satire', 'Declined', 'Outfits','Unorganized', 'AP')
ORDER BY RAND()
LIMIT 20
Then, for each result of the random items, I want to find a corresponding item that is very similar to the random item (around the same rating) but not identical and also one the user has not seen:
SELECT ABS($site_rating-(A.user_votes/A.user_voters)) as diff, (A.user_votes/A.user_voters) as site_rating, B.ID as post_id, B.post_author, B.post_date,E.name as category ,IFNULL(F.count,0) as count
FROM `wp_gdsr_data_article` as A
INNER JOIN `wp_posts` as B ON (A.post_id = B.id)
INNER JOIN wp_term_relationships C ON (B.ID = C.object_id)
INNER JOIN wp_term_taxonomy D ON (C.term_taxonomy_id = D.term_taxonomy_id)
INNER JOIN wp_terms E ON (D.term_id = E.term_id)
LEFT JOIN (
SELECT *,COUNT(*) as count FROM `verus` WHERE ip = '{$_SERVER['REMOTE_ADDR']}'
) as F ON (A.post_id = F.post_id_winner OR A.post_id = F.post_id_loser)
WHERE
E.name = '$category' AND
B.ID <> '$post_id' AND
B.post_type = 'post' AND
B.post_status = 'publish' AND
D.taxonomy='category' AND
E.name NOT IN ('Satire', 'Declined', 'Outfits','Unorganized', 'AP')
ORDER BY count ASC, diff ASC
LIMIT 1
Where the following php variables refer to the result of the previous query
$post_id = $result['post_id'];
$category = $result['category'];
$site_rating = $result['site_rating'];
and $_SERVER['REMOTE_ADDR'] refers to the user's IP.
Is there a way to combine the first query with the 20 additional queries that need to be called to find corresponding items, so that I need just 1 or 2 queries?
Edit: Here is the view that simplifies the joins
CREATE VIEW `versus_random` AS
SELECT (A.user_votes/A.user_voters) as site_rating, B.ID as post_id, B.post_author, B.post_date,E.name as category
FROM `wp_gdsr_data_article` as A
INNER JOIN `wp_posts` as B ON (A.post_id = B.id)
INNER JOIN wp_term_relationships C ON (B.ID = C.object_id)
INNER JOIN wp_term_taxonomy D ON (C.term_taxonomy_id = D.term_taxonomy_id)
INNER JOIN wp_terms E ON (D.term_id = E.term_id)
WHERE
B.post_type = 'post' AND
B.post_status = 'publish' AND
D.taxonomy='category' AND
E.name NOT IN ('Satire', 'Declined', 'Outfits','Unorganized', 'AP')
My attempt now with the view:
SELECT post_id,
(
SELECT INNER_TABLE.post_id
FROM `versus_random` as INNER_TABLE
WHERE
INNER_TABLE.post_id <> OUTER_TABLE.post_id
ORDER BY (SELECT COUNT(*) FROM `versus` WHERE ip = '54' AND (INNER_TABLE.post_id = post_id_winner OR INNER_TABLE.post_id = post_id_loser)) ASC
LIMIT 1
) as innerquery
FROM `versus_random` as OUTER_TABLE
ORDER BY RAND()
LIMIT 20
However the query just timesout and freezes my mysql.
I think it should work like this, but I don't have any Wordpress at hand to test it. The second query that gets the related post is embedded in the other query, when it gets just the related_post_id. The whole query is turned into a subquery itself, given the alias 'X' (although you are free to use 'G', if you want to continue your alphabet.)
In the outer query, the tables for posts and data-article are joined again (RA and RP) to query the relevant fields of the related post, based on the related_post_id from the inner query. These two tables are left joined (and in reverse order), so you still get the main post if no related post was found.
SELECT
X.site_rating,
X.post_id,
X.post_author,
X.post_date,
X.category,
RA.user_votes / RA.user_voters as related_post_site_rating,
RP.ID as related_post_id,
RP.post_author as related_post_author,
RP.post_date as related_post_date,
RP.name as related_category,
FROM
( SELECT
(A.user_votes/A.user_voters) as site_rating,
B.ID as post_id, B.post_author, B.post_date,E.name as category,
( SELECT
RB.ID as post_id
FROM `wp_gdsr_data_article` as RA
INNER JOIN `wp_posts` as RB ON (RA.post_id = RB.id)
INNER JOIN wp_term_relationships RC ON (RB.ID = RC.object_id)
INNER JOIN wp_term_taxonomy RD ON (RC.term_taxonomy_id = RD.term_taxonomy_id)
INNER JOIN wp_terms RE ON (RD.term_id = RE.term_id)
LEFT JOIN (
SELECT *,COUNT(*) as count FROM `verus` WHERE ip = '{$_SERVER['REMOTE_ADDR']}'
) as RF ON (RA.post_id = RF.post_id_winner OR RA.post_id = RF.post_id_loser)
WHERE
RE.name = E.name AND
RB.ID <> B.ID AND
RB.post_type = 'post' AND
RB.post_status = 'publish' AND
RD.taxonomy='category' AND
RE.name NOT IN ('Satire', 'Declined', 'Outfits','Unorganized', 'AP')
ORDER BY count ASC, diff ASC
LIMIT 1) as related_post_id
FROM `wp_gdsr_data_article` as A
INNER JOIN `wp_posts` as B ON (A.post_id = B.id)
INNER JOIN wp_term_relationships C ON (B.ID = C.object_id)
INNER JOIN wp_term_taxonomy D ON (C.term_taxonomy_id = D.term_taxonomy_id)
INNER JOIN wp_terms E ON (D.term_id = E.term_id)
WHERE
B.post_type = 'post' AND
B.post_status = 'publish' AND
D.taxonomy='category' AND
E.name NOT IN ('Satire', 'Declined', 'Outfits','Unorganized', 'AP')
ORDER BY RAND()
LIMIT 20
) X
LEFT JOIN `wp_posts` as RP ON RP.id = X.related_post_id
LEFT JOIN `wp_gdsr_data_article` as RA.post_id = RP.id
I can't test my proposal so take it with the benefit of the doubt. Anyway i hope it could be a valid starting point for some of the issues faced.
I can not imagine a solution that does not pass through a temporary table, cabling onerous computations present in your queries. You could also have the goal to not interfere with the randomization of the first phase. In the following I try to clarify.
I'll start with these rewritings:
-- first query
SELECT site_rating, post_id, post_author, post_date, category
FROM POSTS_COMMON
ORDER BY RAND()
LIMIT 20
-- second query
SELECT ABS(R.site_rating_A - R.site_rating_B) as diff, R.site_rating_B as site_rating, P.post_id, P.post_author, P.post_date, P.category, F.count
FROM POSTS_COMMON AS P
INNER JOIN POSTS_RATING_DIFFS AS R ON (P.post_id = R.post_id_B)
LEFT JOIN (
/* post_id_winner, post_id_loser explicited; COUNT(*) NULL treatment anticipated */
SELECT post_id_winner, post_id_loser, IFNULL(COUNT(*), 0) as count FROM `verus` WHERE ip = '{$_SERVER['REMOTE_ADDR']}'
) as F ON (P.post_id = F.post_id_winner OR P.post_id = F.post_id_loser)
WHERE
P.category = '$category'
AND R.post_id_A = '$post_id'
ORDER BY count ASC, diff ASC
LIMIT 1
with:
SELECT A.post_id_A, B.post_id_B, A.site_rating as site_rating_A, B.site_rating as site_rating_B
INTO POSTS_RATING_DIFFS
FROM POSTS_COMMON as A, POSTS_COMMON as B
WHERE A.post_id <> B.post_id AND A.category = B.category
CREATE VIEW POSTS_COMMON AS
SELECT A.ID as post_id, A.user_votes, A.user_voters, (A.user_votes / A.user_voters) as site_rating, B.post_author, B.post_date, E.name as category
FROM wp_gdsr_data_article` as A
INNER JOIN `wp_posts` as B ON (A.post_id = B.post_id)
INNER JOIN wp_term_relationships C ON (B.ID = C.object_id)
INNER JOIN wp_term_taxonomy D ON (C.term_taxonomy_id = D.term_taxonomy_id)
INNER JOIN wp_terms E ON (D.term_id = E.term_id)
WHERE
B.post_type = 'post' AND
B.post_status = 'publish' AND
D.taxonomy='category' AND
E.name NOT IN ('Satire', 'Declined', 'Outfits','Unorganized', 'AP')
POSTS_COMMON isolates a common view between the two queries.
With POSTS_RATING_DIFFS, a temporary table populated with the ratings combinations and diffs, we have "the trick" of transforming the inequality join criteria on post_id(s) in an equality one (see R.post_id_A = '$post_id' in the second query).
We also take advantage of a temporary table in having precomputed ratings for the combinatory explosion of A.post_id <> B.post_id (with post category equality), and moreover being useful for other sessions.
Also extracting the RAND() ordering in a temporary table could be advantageous. In this case we could limit the ratings combinations and diffs only on the 20 randomly chosen.
Original limiting to one single row in the dependent second level query is done by mean of ordering and limit statements.
The proposed solution avoids elaborating a LIMIT 1 on an ORDER BY resultset in the second level query wich become a subquery.
The single row calculation in the subquery is done by mean of a WHERE criteria on the maximum of a single value calculated from the columns values on which ORDER BY clause is used.
The combination into a single value must be valid in preserving the correct ordering. I'll leave in pseudo-code as:
'<combination of count and diff>'
For example, using combination of the two values into a string type, we could have:
CONCAT(LPAD(CAST(count AS CHAR), 10, '0'), LPAD(CAST(ABS(diff) AS CHAR), 20, '0'))
The structure of the single query would be:
SELECT (Q_LVL_1.user_votes/Q_LVL_1.user_voters) as site_rating_LVL_1, Q_LVL_1.post_id as post_id_LVL_1
, Q_LVL_1.post_author as post_author_LVL_1, Q_LVL_1.post_date as post_date_LVL_1
, Q_LVL_1.category as category_LVL_1, Q_LVL_2.post_id as post_id_LVL_2
, Q_LVL_2.diff as diff_LVL_2, Q_LVL_2.site_rating as site_rating_LVL_2
, Q_LVL_2.post_author as post_author_LVL_2, Q_LVL_2.post_date as post_date_LVL_2
, Q_LVL_2.count
FROM POSTS_COMMON AS Q_LVL_1
, /* 1-row-selection query placed side by side for each Q_LVL_1's row */
(
SELECT CORE_P.post_id, CORE_P.ABS_diff as diff, P.site_rating, P.post_author, P.post_date, CORE_P.count
FROM POSTS_COMMON AS P
INNER JOIN (
SELECT FIRST(CORE_P.post_id) as post_id, ABS(CORE_P.diff) as ABS_diff, CORE_P.count
FROM (
/*
selection of posts with post_id(s) different from first level query,
not already taken and with the topmost value of
'<combination of count and diff>'
*/
) AS CORE_P
GROUP BY CORE_P.count, ABS(CORE_P.diff)
/* the one row selector */
) AS CORE_ONE_LINER ON P.post_id = CORE_ONE_LINER.post_id
) AS Q_LVL_2
ORDER BY RAND()
LIMIT 20
CORE_P selection could have more post_id(s) corresponding to the topmost value '<combination of count and diff>', so the use of GROUP BY and FIRST clauses to reach the single row.
This brings to a possible final implementation:
SELECT (Q_LVL_1.user_votes/Q_LVL_1.user_voters) as site_rating_LVL_1, Q_LVL_1.post_id as post_id_LVL_1
, Q_LVL_1.post_author as post_author_LVL_1, Q_LVL_1.post_date as post_date_LVL_1
, Q_LVL_1.category as category_LVL_1, Q_LVL_2.post_id as post_id_LVL_2
, Q_LVL_2.diff as diff_LVL_2, Q_LVL_2.site_rating as site_rating_LVL_2
, Q_LVL_2.post_author as post_author_LVL_2, Q_LVL_2.post_date as post_date_LVL_2
, Q_LVL_2.count
FROM POSTS_COMMON AS Q_LVL_1
, (
SELECT CORE_P.post_id, CORE_P.ABS_diff as diff, P.site_rating, P.post_author, P.post_date, CORE_P.count
FROM POSTS_COMMON AS P
INNER JOIN
(
SELECT FIRST(CORE_P.post_id) as post_id, ABS(CORE_P.diff) as ABS_diff, CORE_F.count
FROM (
SELECT CORE_RATING.post_id as post_id, ABS(CORE_RATING.diff) as ABS_diff, CORE_F.count
FROM (
SELECT post_id_B as post_id, site_rating_A - site_rating_B as diff
FROM POSTS_RATING_DIFFS
WHERE POSTS_RATING_DIFFS.post_id_A = Q_LVL_1.post_id
) as CORE_RATING
LEFT JOIN (
SELECT post_id_winner, post_id_loser, IFNULL(COUNT(*), 0) as count
FROM `verus`
WHERE ip = '{$_SERVER['REMOTE_ADDR']}'
) as CORE_F ON (CORE_RATING.post_id = CORE_F.post_id_winner OR CORE_RATING.post_id = CORE_F.post_id_loser)
WHERE
POSTS_RATING_DIFFS.post_id_A = Q_LVL_1.post_id
AND '<combination of CORE_F.count and CORE_RATING.diff>'
= MAX (
SELECT '<combination of CORE_F_2.count and CORE_RATING_2.diff>'
FROM (
SELECT site_rating_A - site_rating_B as diff
FROM POSTS_RATING_DIFFS
WHERE POSTS_RATING_DIFFS.post_id_A = Q_LVL_1.post_id
) as CORE_RATING_2
LEFT JOIN (
SELECT post_id_winner, post_id_loser, IFNULL(COUNT(*), 0) as count
FROM `verus`
WHERE ip = '{$_SERVER['REMOTE_ADDR']}'
) as CORE_F_2 ON (CORE_RATING_2.post_id = CORE_F_2.post_id_winner OR CORE_RATING_2.post_id = CORE_F_2.post_id_loser)
) /* END MAX */
) AS CORE_P
GROUP BY CORE_P.count, ABS(CORE_P.diff)
) AS CORE_ONE_LINER ON P.post_id = CORE_ONE_LINER.post_id
) AS Q_LVL_2
ORDER BY RAND()
LIMIT 20
I have a table (edu_posts) which contains posts. The field "post_receiver" usually contains a user_id, but sometimes it may contain an event ID (syntax: event-ID) and I have created a statement like this:
SELECT
p.*,
u.firstname AS post_author_firstname,
u.lastname AS post_author_lastname,
u3.firstname AS receiver_firstname,
u3.lastname AS receiver_lastname,
pl.like_author AS user_likes,
CASE
WHEN p.post_receiver REGEXP '^[a-z]'
THEN
SUBSTRING_INDEX(
SUBSTRING_INDEX(p.post_receiver, '-', 2),
'-',
- 1
)
END
AS event_id,
e.event_name AS event_name
FROM
edu_posts p
LEFT JOIN edu_users u ON u.user_id = p.post_author
LEFT JOIN edu_users u3 ON u3.user_id = p.post_receiver
LEFT JOIN edu_likes pl ON pl.like_entity = p.post_id
LEFT JOIN edu_events e ON e.event_id = event_id
AND pl.like_author = 1
GROUP BY
p.post_id,
pl.like_id
ORDER BY
p.post_date DESC
Have a look at CASE and below in the SELECT statement, and the last LEFT JOIN.
I figured I cannot retrieve data from "event_id" i created in the SELECT statement. So what could I do to LEFT JOIN based on EVENT_ID's value?
Maybe this whole progress is too complicated, and instead it would be better and more effective to make a new MySQL call in the PHP code, if post_receiver is equal to: event-someID?
What are your thoughts? Thanks in advance!
I have an MySQL statement that performs an inner SELECT and returns the result as a pseudo column. I’d like to use the result of this pseudo column in my WHERE clause. My current SQL statement looks like this:
SELECT
product.product_id,
product.range_id,
product.title,
product.image,
product.image_text,
product.friendly_url,
attribute.comfort_grade_id,
category.category_id,
category.category AS category_name,
category.friendly_url AS category_friendly_url,
(SELECT price_now FROM product_bedding_sizes AS size
WHERE size.product_id = product.product_id
ORDER BY size.price_now ASC LIMIT 1) AS price
FROM
products AS product
LEFT JOIN
categories AS category ON product.category_id = category.category_id
LEFT JOIN
product_bedding_attributes AS attribute
ON product.product_id = attribute.product_id
$where
$order
LIMIT
?,?
However, I get the following error message when running the query:
#1054 - Unknown column 'price' in 'where clause'
How can I get around this and actually use the value of price in my WHERE clause?
The WHERE clause is evaluated before the SELECT clause, so it doesn't say the alias name. You have to do the filter by the WHERE clause in an outer query like this:
SELECT *
FROM
(
SELECT
product.product_id,
product.range_id,
product.title,
product.image,
product.image_text,
product.friendly_url,
attribute.comfort_grade_id,
category.category_id,
category.category AS category_name,
category.friendly_url AS category_friendly_url,
(SELECT price_now
FROM product_bedding_sizes AS size
WHERE size.product_id = product.product_id
ORDER BY size.price_now ASC
LIMIT 1) AS price
FROM
...
) AS sub
WHERE price = ... <--- here it can see the price alias.
See this for more details:
My SQL Query Order of Operations.
Or: You can join that table, instead of a correlated subquery like this:
SELECT
product.product_id,
product.range_id,
product.title,
product.image,
product.image_text,
product.friendly_url,
attribute.comfort_grade_id,
category.category_id,
category.category AS category_name,
category.friendly_url AS category_friendly_url,
size.price_now
FROM
products AS product
LEFT JOIN
(
SELECT product_id, MIN(price_now) AS price
FROM product_bedding_sizes
GROUP BY product_id
) AS size ON size.product_id = product.product_id
LEFT JOIN
categories AS category ON product.category_id = category.category_id
LEFT JOIN
product_bedding_attributes AS attribute ON product.product_id = attribute.product_id
$where price = ----;
Try using a variable:
#price:= (SELECT price_now
FROM product_bedding_sizes AS size
WHERE size.product_id = product.product_id
ORDER BY size.price_now ASC LIMIT 1) AS price;
Then reference it as
WHERE #price > 9000;
if you have
WHERE price > 0 AND price` <= 199`
in your where clause
then try do this with HAVING clause
like that
$HAVING
//-- where $having = HAVING price > 0 AND price <= 199
I've been at this for a bit now. Basically, I'm needing to add a derived column to count the hits to a weblog entry in the database. The problem is, the hits are being totaled and shown on only on the first record. Any Ideas? I've emboldened the parts of the query I'm talking about. The query is below:
SELECT DISTINCT(t.entry_id),
exp_categories.rank,
**exp_hits.hits,**
t.entry_id,
t.weblog_id,
t.forum_topic_id,
t.author_id,
t.ip_address,
t.title,
t.url_title,
t.status,
t.dst_enabled,
t.view_count_one,
t.view_count_two,
t.view_count_three,
t.view_count_four,
t.allow_comments,
t.comment_expiration_date,
t.allow_trackbacks,
t.sticky,
t.entry_date,
t.year,
t.month,
t.day,
t.entry_date,
t.edit_date,
t.expiration_date,
t.recent_comment_date,
t.comment_total,
t.trackback_total,
t.sent_trackbacks,
t.recent_trackback_date,
t.site_id as entry_site_id,
w.blog_title,
w.blog_name,
w.search_results_url,
w.search_excerpt,
w.blog_url,
w.comment_url,
w.tb_return_url,
w.comment_moderate,
w.weblog_html_formatting,
w.weblog_allow_img_urls,
w.weblog_auto_link_urls,
w.enable_trackbacks,
w.trackback_use_url_title,
w.trackback_field,
w.trackback_use_captcha,
w.trackback_system_enabled,
m.username,
m.email,
m.url,
m.screen_name,
m.location,
m.occupation,
m.interests,
m.aol_im,
m.yahoo_im,
m.msn_im,
m.icq,
m.signature,
m.sig_img_filename,
m.sig_img_width,
m.sig_img_height,
m.avatar_filename,
m.avatar_width,
m.avatar_height,
m.photo_filename,
m.photo_width,
m.photo_height,
m.group_id,
m.member_id,
m.bday_d,
m.bday_m,
m.bday_y,
m.bio,
md.*,
wd.*
FROM exp_weblog_titles AS t
LEFT JOIN exp_weblogs AS w ON t.weblog_id = w.weblog_id
LEFT JOIN exp_weblog_data AS wd ON t.entry_id = wd.entry_id
LEFT JOIN exp_members AS m ON m.member_id = t.author_id
LEFT JOIN exp_member_data AS md ON md.member_id = m.member_id
LEFT JOIN exp_category_posts ON wd.entry_id = exp_category_posts.entry_id
**LEFT JOIN
(
SELECT COUNT(*) AS hits, exp_hits.entry_id FROM exp_hits ORDER BY exp_hits.entry_id
) exp_hits ON t.entry_id = exp_hits.entry_id**
LEFT JOIN
(
SELECT exp_categories.cat_id, cat_name as rank
FROM exp_categories
WHERE exp_categories.group_id = '9'
) exp_categories ON exp_categories.cat_id = exp_category_posts.cat_id
WHERE t.entry_id IN (2,3,4) ORDER BY exp_categories.rank DESC, **exp_hits.hits DESC**, entry_date desc
Try changeing the subselect to
SELECT COUNT(*) AS hits,
exp_hits.entry_id
FROM exp_hits
GROUP BY exp_hits.entry_id
Out of curiosity, is your hits functionality something that can't be accomplished with the view_count_one/two/three/four fields already present in the database and supported by ExpressionEngine template tags?