The query below is searching for posts that are followed by users (if user follows category, user or topic).
It is working if it doesn't use $time_interval.
I would like to select posts from a certain period of time (last week, last month etc.).
I hardcoded 1 month and $filter for this example. But as soon as I try to select posts from last month, the query stops working.
I tried with methods that I used in other places, but this query is much more complex and by even putting the query to work to this point was very long process of errors, so I am not sure if it is written in the best possible way.
$current_user_id = get_current_user_id();
$term_relat_table = ;// table with term relationships
$topic_follow_table = ;// contains which topic user follows
$cat_follow_table = ;// contains which category user follows
$posts_table = ;// table with posts
$user_follow_user_table = ;// contains which users current user follows
$votes_stats_table = ;// table with votes
$perPage = 10; // hardcoded for this example
$orderby = "ORDER BY vote_rating DESC, total_votes DESC"; // hardcoded for this example
$time_interval = date('Y-m-d H:i:s', strtotime('-1 month')); // wasnt able to include in query
//I tried placing p.post_date > $time_interval in different places in query but none seem to work.
$all_results = $wpdb->get_results($wpdb->prepare("
SELECT v.topic_id AS post_id
, v.votes_rating AS vote_rating
, v.total_votes AS total_votes
FROM $votes_stats_table v
JOIN
( SELECT tf.discussion_id AS post_id
FROM $topic_follow_table AS tf
WHERE tf.current_user = %d
UNION ALL
SELECT p.ID AS post_id
FROM $user_follow_user_table AS uf
JOIN $posts_table AS p
ON p.post_author = uf.followed_user
WHERE uf.current_user = %d
-- tried placing p.post_date > %s here, and $time_interval below next to other variables
UNION ALL
SELECT r.object_id AS post_id
FROM $term_relat_table AS r
JOIN $cat_follow_table AS cf
ON cf.cat_id = r.term_taxonomy_id
WHERE cf.user_id = %d
) AS i
ON i.post_id = v.topic_id
GROUP
BY v.topic_id
$orderby
LIMIT %d
OFFSET $offset", $current_user_id, $current_user_id, $current_user_id, $perPage));
Related
I am trying to only get rows from video_index that belongs to a specific category from category_video_rel and order the result by COUNT of view count. This is the query I'm using:
SELECT
COUNT(DISTINCT view_count.id) AS count,
view_count.remove,
view_count.video_id,
video_index.id AS video_id,
video_index.active,
video_index.remove,
video_index.title AS title,
video_index.date_published AS date_published,
category_video_rel.active,
category_video_rel.remove,
category_video_rel.video_id AS cv_video_id,
category_video_rel.category_id AS category_id
FROM
view_count JOIN video_index
ON view_count.video_id = video_index.id,
category_video_rel JOIN video_index AS v
ON category_video_rel.video_id = v.id
WHERE
view_count.remove = '0' AND
video_index.active = '1' AND
video_index.remove = '0' AND
video_index.date_published <= '$current_time' AND
category_video_rel.category_id = '$category_id' AND
category_video_rel.active = '1' AND
category_video_rel.remove = '0'
GROUP BY
video_index.id
ORDER BY
count DESC
The problem is it outputs all the rows from video_index with a view count higher than 0 regardless of the category. Basically, it's ignoring "category_video_rel.category_id = '$category_id'" in the WHERE condition.
I have no idea what I'm doing wrong, please help.
Your FROM clause is mixing old style joins and new style joins
Instead try:
FROM
view_count JOIN video_index
ON view_count.video_id = video_index.id
JOIN category_video_rel
ON category_video_rel.video_id = video_index.id
I have a table with news items, I have another table with media_types, I want to make one simple query that reads the media_types table and count for each record how many news_items exist.
The result will be turned into a json response that I will use for a chart, this is my SQLstatement
SELECT
gc.country AS "country"
, COUNT(*) AS "online"
FROM default_news_items AS ni
JOIN default_news_item_country AS nic ON (nic.id = ni.country)
JOIN default_country AS c ON (nic.country = c.id)
JOIN default_geo_country AS gc ON (gc.id = c.geo_country)
LEFT JOIN default_medias ON (m.id = ni.media)
WHERE TRUE
AND ni.deleted = 0
AND ni.date_item > '2013-10-23'
AND ni.date_item < '2013-10-29'
AND gc.country <> 'unknown'
AND m.media_type = '14'
GROUP BY gc.country
ORDER BY `online` desc LIMIT 10
This is the json respond I create from the mysql respond
[
{"country":"New Zealand","online":"7"},
{"country":"Switzerland","online":"1"}
]
How do I add print and social data to my output like this
I would like the json respond look like this
[
{"country":"New Zealand","online":"7", "social":"17", "print":"2"},
{"country":"Switzerland","online":"1", "social":"7", "print":"1"}
]
Can I use the count (*) in the select statement to do something like this
COUNT( * ) as online, COUNT( * ) as social, COUNT( * ) as print
Is it possible or do I have to do several SQL statement to get the data I'm looking for?
This is the general structure:
SELECT default_geo_country.country as country,
SUM(default_medias.media_type = 14) as online,
SUM(default_medias.media_type = XX) as social,
SUM(default_medias.media_type = YY) as print
FROM ...
JOIN ...
WHERE ...
GROUP BY country
I think you want conditional aggregation. Your question, however, only shows the online media type.
Your query would be more readable by using table aliases and removing the back quotes. Also, if media_type is an integer, then you should not enclose the constant for comparison in single quotes -- I, for one, find it misleading to compare a string constant to an integer column.
I suspect this is the way you want to go. Where the . . . is, you want to fill in with the counts for the other media types.
SELECT default_geo_country.country as country,
sum(media_type = '14') as online,
sum(default_medias.media_type = XX) as social,
sum(default_medias.media_type = YY) as print
. . .
FROM default_news_items ni JOIN
default_news_item_country nic
ON nic.id = ni.country JOIN
default_country dc
ON nic.country = dc.id JOIN
default_geo_country gc
ON gc.id = dc.geo_country LEFT JOIN
default_medias dm
ON dm.id = dni.media
WHERE ni.deleted = '0'
AND ni.date_item > '2013-10-23'
AND ni.date_item < '2013-10-29'
AND gc.country <> 'unknown'
GROUP BY gc.country
ORDER BY online desc
LIMIT 10
I have the following code:
$params = array();
$query_questions_visibles = questionTable::getInstance()->createQuery("q")
->select("q.*, ua.*, a.*, u.*, c.*")
->leftJoin("q.Answers a")
->leftJoin("a.UserAnswers ua")
->Where("q.blocked = false")
->andWhere("ua.user_id = :user_id")
->orderBy("q.id DESC")
->groupBy("q.id");
//Subquery --> Calculates when a question is active or not
$format = sfConfig::get("app_datetime_format");
$active_time = date($format, strtotime(sfConfig::get("app_question_active_time")));
$sub_query_is_active = $query_questions_visibles->createSubQuery()
->select("MAX(ua0.created_at)")
->from("question q0")
->leftJoin("q0.Answers a0")
->leftJoin("a0.UserAnswers ua0")
->where("q0.id = q.id");
$query_questions_visibles->addSelect("COALESCE((".$sub_query_is_active.") > :active_time, false) as Active");
//Set param values
$params["user_id"] = $guardUser->id;
$params["active_time"] = $active_time;
$result = $query_questions_visibles->execute($params);
The previous code works as expected.
Generated SQL is complete and works:
SELECT q.id AS q__id, q.user_id AS q__user_id, q.category_id AS q__category_id, q.gender_restriction AS q__gender_restriction, q.question AS q_question, q.photo AS q_photo, q.latitude AS q_latitude, q.longitude AS q_longitude, q.multiple AS q_multiple, q.blocked AS q_blocked, q.created_at AS q__created_at, q.updated_at AS q__updated_at, a.id AS a__id, a.question_id AS a__question_id, a.text AS a_text, u.id AS u_id, u.user_id AS u__user_id, u.answer_id AS u__answer_id, u.created_at AS u__created_at, u.updated_at AS u__updated_at, COALESCE((SELECT MAX(u2.created_at) AS u2__0 FROM question q2 LEFT JOIN answer a2 ON q2.id = a2.question_id LEFT JOIN user_answer u2 ON a2.id = u2.answer_id WHERE (q2.id = q.id)) > :active_time, 0) AS u2__0 FROM question q LEFT JOIN answer a ON q.id = a.question_id LEFT JOIN user_answer u ON a.id = u.answer_id WHERE (q.blocked = 0 AND u.user_id = :user_id) GROUP BY q.id ORDER BY q.id DESC
But, if I want to limit results, I modify the end lines as:
$query_questions_visibles->limit(10);
$result = $query_questions_visibles->execute($params);
Doctrine throws an error:
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
at Doctrine_Connection->execute('SELECT DISTINCT q2.id FROM question q2 LEFT JOIN answer a2 ON q2.id = a2.question_id LEFT JOIN user_answer u2 ON a2.id = u2.answer_id WHERE q2.blocked = 0 AND u2.user_id = :user_id GROUP BY q2.id ORDER BY q2.id DESC LIMIT 10', array('user_id' => '1', 'active_time' => '2013-03-17 17:12:12')) in SF_ROOT_DIR\lib\vendor\symfony\lib\plugins\sfDoctrinePlugin\lib\vendor\doctrine\Doctrine\Query.php line 1290 ...
My purpose is only limit the query to 10 results, ¿where is my Subquery with COALESCE and MAX functions? ¿Why there's a SELECT DISTINCT who I never specified? ¿Why is selecting only q.id?
I spend all day trying to figure it out, i have no answer...
Any Ideas why setting a limit causes this?
When you add limit() to the Doctrine query then the Doctrine internals create in fact two queries. The first one select a limited set of distinct ids based on the conditions of your query. The second query selects the actual objects limiting the select to the ids found with the first query.
The problem with your query is that you use params inside of the select part, which is not used in the first query.
The only solutuion that comes to my mind is to add the value of the active_time parameter directly to the select part, without using the named param. It might not be the nicest solution but I can't think of a different one right now. The addSelect() does not accept additional parameters like where() does which could fix the issue (with where() you can use: ->where('field > ?', $value)).
I have two sql tables one which has users and the other which has messages.
Right now my query is :
SELECT users.memberid,users.username,users.profileimage,users.gender,message.messagebody, message.fromid,message.toid,message.messageid
FROM message,users
WHERE message.fromid = users.memberid AND message.toid = '$id' AND recieverdeleted='0'
ORDER BY datetime DESC LIMIT 55
Right now what is being returned is all the information for everymessage regardless of formid(sender's id)
The thing is , I want to only display the most recent message for every from id ..Kind of like how Facebook only shows you the most recent message that friend x has sent you, and not all the messages. I will work on showing all messages after the user has clicked on his friend's most recent message.
Thanks
Well, you tried. That's good.
SELECT u.memberid
, u.username
, u.profileimage
, u.gender
, m.messagebody
, m.fromid
, m.toid
, m.messageid
FROM users u
JOIN message m
ON m.fromid = u.memberid
JOIN (SELECT fromid,toid,MAX(datetime) max_datetime FROM message GROUP BY fromid,toid) n
ON n.fromid = m.fromid
AND n.toid = m.toid
AND n.max_datetime = m.datetime
WHERE message.toid = $id
AND recieverdeleted = 0
ORDER
BY datetime DESC LIMIT 55;
At first join the two tables than apply order by because at this moment the command is not sure for which table you want to apply the ordering.
Or better you create an intermediate table from the selection of two tables and then apply the ordering.
Something like:
SELECT username,messagebody,fromid FROM(
SELECT users.memberid,users.username,users.profileimage,users.gender,message.messagebody, message.fromid,message.toid,message.messageid,message.datetime
FROM message,users
WHERE message.fromid = users.memberid AND message.toid = '$id' AND recieverdeleted='0' )INTERMEDIATE_TABLE ORDER BY datetime DESC
I might be wrong in syntax as I have done sql codes a long ago but you should try something very similar like this.
Try this its working
SELECT m1.*
FROM table_name m1
INNER JOIN (SELECT MAX(senddate) AS senddate,
IF(member_id2 = 3, member_id1, member_id2 ) AS user
FROM table_name
WHERE (member_id1 = 3 AND delete1=0) OR
(member_id2 = 3 AND delete2=0)
GROUP BY user) m2
ON m1.senddate = m2.senddate AND
(m1.member_id1 = m2.user OR m1.member_id2 = m2.user)
WHERE (member_id1 = 3 AND delete1=0) OR
(member_id2 = 3 AND delete2=0)
ORDER BY m1.senddate DESC
Try this::
SELECT users.memberid,users.username,users.profileimage,users.gender,message.messagebody, message.fromid,message.toid,message.messageid
FROM message inner join users on (message.fromid = users.memberid)
where message.toid = '$id' AND recieverdeleted='0'
ORDER BY message_datetime DESC limit 1
I'm trying to count only unique terms as a TOTAL count.
This is the original query and it works fine
->select('DISTINCT search_tags.term AS t_name, nbr', FALSE)
->from('search_tags LEFT JOIN (SELECT term AS tk, COUNT(search_tags.term) AS nbr FROM search_tags GROUP BY search_tags.term) AS TR ON search_tags.term = TR.tk ')
->where('search_tags.dt_added >=', '2011-08-01 09:48:54')
->where('search_tags.dt_added <=', '2011-09-02 09:48:54');
// returns: [twitter,12],[facebook,6].....
The thing is that this code runs a datatable (datatable.net) so the datatable removes the select line and change it to:
SELECT COUNT(*) AS numrows
FROM (search_tags LEFT JOIN (SELECT term AS tk, COUNT(search_tags.term) AS nbr FROM search_tags GROUP BY search_tags.term) AS TR ON search_tags.term = TR.tk)
WHERE `search_tags`.`dt_added` >= '2011-08-01 09:48:54'
AND `search_tags`.`dt_added` <= '2011-09-02 09:48:54'
// returns the same [twitter,12],[facebook,6]..... BUT the pagination is broken.
So the datatable can count the rows and use it as a pagination param.
But when it removes the select, it get all the rows as the DISTINCT is not there anymore.
I'm sleep deprived so I'm like stuck on try and error forever. Please help lol :P
Sorted out
->select('DISTINCT st5.term AS t_name, n_ocurrences', FALSE)
->from("search_tags AS st4
RIGHT OUTER JOIN (SELECT DISTINCT st.term, n_ocurrences
FROM search_tags AS st
JOIN
(SELECT term AS n_term, COUNT(term) AS n_ocurrences
FROM search_tags AS st2
GROUP BY st2.term)
AS st3 ON st3.n_term = st.term
WHERE st.dt_added >= '$min'
AND st.dt_added <= '$max') AS st5 ON st5.term = 1");
Had to add some inception selects to retrieve the right amount.
Now I need to count the UNIQUE n_ocurrences under the $min, $max as the n_ocurrences is returning only the overall count.