SQL joining Thread with post issue how would you solve it - sql

I need help
$sql = "SELECT
topics.topic_id,
topics.topic_subject,
topics.topic_date,
topics.topic_cat,
topics.topic_by,
topics.topic_open_close,
topics.topic_pin
FROM
topics
LEFT JOIN posts ON topics.topic_id = posts.post_topic_id
WHERE
topics.topic_cat = '". $_GET['id']."' AND topics.topic_pin = '0' ORDER BY posts.post_date DESC;
my SQL is ORDERING the Topics base on post date. the problem I'm having is that when I reply more than 1 time, lets say 3 replies, it shows 3 of the same threads.
the purpose I'm trying to archive with this Query is to bump up the thread by posting base on post_date. its doing the job. It's its just showing more than one thread.
how would you guys get write this Query to do the job?

Seems you are joining the posts table even thought you are not displaying some of its columns. But if you want to display 1 topic based on the latest post date, you can join the max(post_date) via subquery.
SELECT
topics.topic_id,
topics.topic_subject,
topics.topic_date,
topics.topic_cat,
topics.topic_by,
topics.topic_open_close,
topics.topic_pin
FROM topics
INNER JOIN
(SELECT max(post_date) post_date, post_topic_id FROM posts GROUP BY post_topic_id) t2 ON topics.topic_id = t2.post_topic_id
WHERE
topics.topic_cat = '". $_GET['id']."' AND topics.topic_pin = '0'

I solved it the long way. I needed to get it done. My plan was to make it short.
with a SQL Query.
I have a functions.php folder to run all my functions thru out the project.
so i created a function inside the functions.php to run all query and not having to repeat myself.
examp:
function query($sql, $conn){
$result = mysqli_query($conn, $sql);
if(!$result){
echo 'There is a Error in the SQL '. mysqli_error($conn);
}else{
return $result;
}
}
I added a column on Topics called "Topic_last_post_date". Every time someone post if the Query to post the post goes successfully it will execute the query to update the "Topic_last_post_date" on the assigned topic.
//posting Query ect ect..
if(!$result_of_query){
echo'Error';
}else{
$stamp_post_date_on_Topic = query("UPDATE topics SET topic_last_post_date = NOW() WHERE topic_id='".$topicid."' ", $conn);}
then I ended using the this query to display the topic DESC = Descending starting from the last to "Topic_last_post_date" posted.
$sql = "SELECT
topic_id,
topic_subject,
topic_date,
topic_cat,
topic_by,
topic_open_close,
topic_pin,
topic_last_post_date
FROM
topics
WHERE
topic_cat = '". $_GET['id']."' AND topic_pin = '0' ORDER BY topic_last_post_date DESC LIMIT ".$offset.", ".$no_of_records_per_page." ";
I hope it help someone! thanks guys

Related

I need to convert to codeigniter3 active record syntax

I need to join main (4-5) tables and get the latest from the inner join table to get the project current status.
investor have many investments
investments have many investment_details
investment_details has many status through project status
Select
siv.company_name
, siv.full_name
, si.permit_number
, si.project_name
, sid.investment_detailed_id
, sis.project_status_id
, sps.project_status_name
From sma_investors siv
Join sma_investments si
On siv.investor_id = si.investment_id
Join sma_investment_details sid
On si.investment_id = sid.investment_id
Inner Join sma_investment_status sis
On sis.investment_status_id = (
Select investment_status_id
From sma_investment_status s
Where s.investment_detailed_id = sid.investment_detailed_id
Order BY investment_status_id DESC LIMIT 1)
Join sma_project_status sps
On sis.project_status_id = sps.project_status_id
This works fine but I can't convert it the CI3.
There is no advantage to using Query Builder (QB) unless you need parts of the query to be written differently due to some condition. QB is also useful if you want user inputs to be automatically escaped. Otherwise, you simply run a whole lot of extra code that leads to the exact same SQL statement string you already have.
In your case, the sub-select will make the conversion even more difficult to accomplish and add a lot of extra code to be executed.
My advice is to keep it simple and use db->query(), e.g.
$sql = "Select siv.company_name, siv.full_name, si.permit_number, si.project_name
, sid.investment_detailed_id, sis.project_status_id, sps.project_status_name
From sma_investors siv
Join sma_investments si On siv.investor_id = si.investment_id
Join sma_investment_details sid On si.investment_id = sid.investment_id
Inner Join sma_investment_status sis On sis.investment_status_id = (
Select investment_status_id From sma_investment_status s
Where s.investment_detailed_id = sid.investment_detailed_id
Order BY investment_status_id DESC LIMIT 1)
Join sma_project_status sps On sis.project_status_id = sps.project_status_id";
$query = $this->db->query($sql);
if(! $query) // might be false if query fails
{
return null;
}
return $query->row(); // one row of data
I finally come up with my own solution and stick to the QB codding standard and it works as i expected
$q = $this->db->select('*')
->from('investors')
->join('investments', `enter code here`'investors.investor_id=investments.investment_id')
->join('investment_details as sid', 'investments.investment_id=sid.investment_id')
->join('investment_status', 'investment_status.investment_status_id=(select '.$this->db->dbprefix('investment_status').'.investment_status_id from '.$this->db->dbprefix('investment_status').' where '.$this->db->dbprefix('investment_status').'.investment_detailed_id=sid.investment_detailed_id order by '.$this->db->dbprefix('investment_status').'.investment_status_id Desc limit 1)', 'inner')
->join('project_status', 'investment_status.project_status_id=project_status.project_status_id')
->where('sid.company_type_id', 1)
->order_by('investments.investment_id', 'desc')
->limit(5)
->get();

Optimizing a request doing tons of exclusions

I have a huge and dirty SQL request doing many exclusions and I feel bad about it. Perhaps, you know a better way to proceed.
Here's a part of my request:
select name, version, iteration, score
from article, articlemaster
where article.idmaster = articlemaster.id
and article.id not in (select article.id
from article, spsarticlemaster
where article.idmaster = articlemaster.id
and articlemaster.name = 'nameOfMyArticle'
and article.version = 'A'
and article.state = 'CONTINUE')
and article.id not in....
and article.id not in....
You think it doesn't look that bad ? Actually, this is only a portion of the request, the "and spsarticle.id not in ...." exclude one article, and i got more than 1000 to exclude, so i'm using a java program to append the other 999.
Any idea how could i make a light version of this abomination ?
You might be better off loading all of the articles to exclude into a temporary table, then joining that table in to your query.
For example, create exclude_articles:
name version state
---- ------- -----
nameOfMyArticle A CONTINUE
Then exclude its results from the query:
select
article.name,
article.version,
article.iteration,
article.score
from
article
join articlemaster
on article.idmaster = articlemaster.id
where
not exists (
select 1
from article article2
join articlemaster articlemaster2
on article2.idmaster = articlemaster2.id
join exclude_articles
on articlemaster2.name = exclude_articles.name
and article2.version = exclude_articles.version
and article2.state = exclude_articles.state
where article.id = article2.id)
This is all assuming that the version and state are actually necessary for the exclusion logic. It would be a much easier case if the name is unique.
If you're using Java to create the query and process the results, then why not do all the complicated logic in Java? Just ask the database for all the articles matching some basic criterion (or maybe you really do want to read through all of them) and then filter the results:
select am.name, a.version, a.iteration, a.score, a.state
from article a, articlemaster am
where a.idmaster = am.id
and <some other basic criteria>
Then in Java loop over all the results (sorry, my Java is super rusty) and filter out the ones you don't want:
ArrayList recordList = ArrayList();
ArrayList finalList = ArrayList();
for (record in recordList) {
if (! filterThisRecord(record)) {
finalList.append(record);
}
}

Convert a SQL query in Java Persistence Query Language (JPQL)

I'm having a little problem to convert this SQL query to JPQL:
select max(datePurchase) from purchases where userId = id and date_trunc('day',datePurchase)
in (select distinct (date_trunc('day',datePurchase)) as day from purchases where userId = id and datePurchase < initialDate and datePurchase > finalDate) group by date_trunc('day',datePurchase)
This sql is working well, that returns de last purchase per day made from a user. I tried to do the same, in JPQL:
Query query = em.createQuery("SELECT u MAX(u.datePurchase) FROM Purchases u WHERE u.userId.id = :id AND FUNC('day',u.datePurchase)" +
"IN (SELECT DISTINCT (FUNC('day',u.datePurchase)) AS day FROM Purchases WHERE u.userId.id = :id AND u.datePurchase < :finalDate AND u.datePurchase > :inicialDate) GROUP BY FUNC('day',u.datePurchase)");
query.setParameter("id", idUsuario);
query.setParameter("dataInicial", dataInicial);
query.setParameter("dataFinal", dataFinal);
List<MovSaldo> saldos = (List<MovSaldo>) query.getResultList();
em.getTransaction().commit();
The errors are:
"The IN expression does not have a valid expression." "An identification variable must be provided for a range variable declaration."
Probably is not something very difficult, but i have already spent a little frustrating time in it. Can someone please help me?
Although the answer is probably late for you I still posted it because it might help someone in the future.
In the nested select you have to put an identifier for the entity you are working with: FROM Purchases p and update things like (FUNC('day',u.datePurchase)) to (FUNC('day',p.datePurchase))
Best!

Codeigniter SQL Join with multiple ON clauses?

This is the SQL query displayed by codeigniter:
SELECT * FROM (status_updates) JOIN friend_connections ON ((
status_updates.userid=friend_connections.userid) OR
(status_updates.userid=friend_connections.friend_id)) WHERE
status_updates.enabled = "1" AND friend_connections.enabled = "1"
ORDER BY status_updates.date desc, status_updates.time desc LIMIT 20
The Codeigniter commands i used were:
$this->db->from('status_updates');
$this->db->order_by("status_updates.date", "desc");
$this->db->order_by("status_updates.time", "desc");
$this->db->limit(20);
$this->db->join('status_updates', '((status_updates.userid=friend_connections.userid) OR (status_updates.userid=friend_connections.friend_id))');
What i'm trying to do is select everything in two tables, status_updates and friend_connections. status_updates has the one column userid which i want to match with either userid or friend_id from friend_connections. Can someone tell me how i can do this please?
Also i noticed that codeigniter removes the two opening parentheses after the ON command in the above sql query.
Copy of your own answer in order to remove this from the unanswered stack:
$sql = "SELECT * FROM (status_updates) JOIN friend_connections ON ((status_updates.userid=friend_connections.userid) OR (status_updates.userid=friend_connections.friend_id)) WHERE status_updates.enabled = "1" AND friend_connections.enabled = "1" ORDER BY status_updates.date desc, status_updates.time desc LIMIT 20";
$status = $this->db->query($sql);
Please don't upvote. It's not my answer.

Django annotate() multiple times causes wrong answers

Django has the great new annotate() function for querysets. However I can't get it to work properly for multiple annotations in a single queryset.
For example,
tour_list = Tour.objects.all().annotate( Count('tourcomment') ).annotate( Count('history') )
A tour can contain multiple tourcomment and history entries. I'm trying to get how many comments and history entries exist for this tour. The resulting
history__count and tourcomment__count
values will be incorrect. If there's only one annotate() call the value will be correct.
There seems to be some kind of multiplicative effect coming from the two LEFT OUTER JOINs. For example, if a tour has 3 histories and 3 comments, 9 will be the count value for both. 12 histories + 1 comment = 12 for both values. 1 history + 0 comment = 1 history, 0 comments (this one happens to return the correct values).
The resulting SQL call is:
SELECT `testapp_tour`.`id`, `testapp_tour`.`operator_id`, `testapp_tour`.`name`, `testapp_tour`.`region_id`, `testapp_tour`.`description`, `testapp_tour`.`net_price`, `testapp_tour`.`sales_price`, `testapp_tour`.`enabled`, `testapp_tour`.`num_views`, `testapp_tour`.`create_date`, `testapp_tour`.`modify_date`, `testapp_tour`.`image1`, `testapp_tour`.`image2`, `testapp_tour`.`image3`, `testapp_tour`.`image4`, `testapp_tour`.`notes`, `testapp_tour`.`pickup_time`, `testapp_tour`.`dropoff_time`, COUNT(`testapp_tourcomment`.`id`) AS `tourcomment__count`, COUNT(`testapp_history`.`id`) AS `history__count`
FROM `testapp_tour` LEFT OUTER JOIN `testapp_tourcomment` ON (`testapp_tour`.`id` = `testapp_tourcomment`.`tour_id`) LEFT OUTER JOIN `testapp_history` ON (`testapp_tour`.`id` = `testapp_history`.`tour_id`)
GROUP BY `testapp_tour`.`id`
ORDER BY `testapp_tour`.`name` ASC
I have tried combining the results from two querysets that contain a single call to annotate (), but it doesn't work right... You can't really guarantee that the order will be the same. and it seems overly complicated and messy so I've been looking for something better...
tour_list = Tour.objects.all().filter(operator__user__exact = request.user ).filter(enabled__exact = True).annotate( Count('tourcomment') )
tour_list_historycount = Tour.objects.all().filter( enabled__exact = True ).annotate( Count('history') )
for i,o in enumerate(tour_list):
o.history__count = tour_list_historycount[i].history__count
Thanks for any help. Stackoverflow has saved my butt in the past with a lot of already-answered questions, but I wasn't able to find an answer to this one yet.
Thanks for your comment. That didn't quite work but it steered me in the right direction. I was finally able to solve this by adding distinct to both Count() calls:
Count('tourcomment', distinct=True)
tour_list = Tour.objects.all().annotate(tour_count=Count('tourcomment',distinct=True) ).annotate(history_count=Count('history',distinct=True) )
You have to add distinct=True to get the proper result else it will return the wrong answer.
I can't guarantee that this will solve your problem, but try appending .order_by() to your call. That is:
tour_list = Tour.objects.all().annotate(Count('tourcomment')).annotate(Count('history')).order_by()
The reason for this is that django needs to select all the fields in the ORDER BY clause, which causes otherwise identical results to be selected. By appending .order_by(), you're removing the ORDER BY clause altogether, which prevents this from happening. See the aggregation documentation for more information on this issue.