SQL search query in relations tables - php

I am trying to make an sql search query to return only ORDERS that match my search keyword. The issue is that i also need to search in every comments body for each order and if a result is found in that comment the order for that comment should be selected. The tables looks like this in a simplified way:
ORDERS:
ID = 95
title = first order
COMMENT RELATIONS:
id = 1241
comment_id = 500
target_id = 95
type = order
COMMENTS:
id = 500
body = this is the first comment
So if i searched for "first comment" the order with id 95 should be selected.
My current attempt seems to select more then order but also their comments and relations? This is how my current attempt looks like.
$query = 'SELECT DISTINCT *
FROM orders as o
LEFT JOIN comment_relations as cr ON o.id = target_id
LEFT JOIN comments as c ON cr.comment_id = c.id
WHERE o.id LIKE :keyword OR o.title LIKE :keyword OR c.body LIKE :keyword';

Not sure which database you are using but in most databases you can use the table alias follow by * for selecting only one table.
'SELECT DISTINCT o.*
FROM orders as o
LEFT OUTER JOIN comment_relations as cr ON o.id = target_id
LEFT OUTER JOIN comments as c ON cr.comment_id = c.id
WHERE o.id LIKE :keyword OR o.title LIKE :keyword OR c.body LIKE :keyword';

As per your concept i create 3 demo tables in phpmyadmin which description is here.
1.orders have columns (id,title).
2.comment_relations have columns (id,comment_id,target_id,type).
3.comments have columns (id,body).
This is SQL Query for fetch records from order by match keyword from comments table.
select DISTINCT o.* from orders o LEFT JOIN comment_relations cr ON o.id=cr.target_id LEFT JOIN comments c ON c.id=cr.comment_id where body LIKE '%keyword%'
On applying this query by replace your keyword at place of keyword you get this result.
Here i match keyword "first comment"

Related

Error joining 3 tables php/sql

I'm new to this, so I know I'm missing something simple, but I can't figure it out. I'm trying to join 3 tables together and I've got it working with 2 joins, but when combined in the same query, there ends up being an error.
My 3 tables are:
TBL_Authors
Author_ID
Author_Name
TBL_Publishers
Publisher_ID
Publisher_Name
TBL_Books
Title
Author_ID
Publisher_ID
ISBN
Genre
Price
Cost
Rating
What I have that isn't working:
$query = 'SELECT * FROM TBL_PUBLISHERS
JOIN TBL_BOOKS ON TBL_PUBLISHERS.Publisher_ID = TBL_BOOKS.Publisher_ID
SELECT * FROM TBL_AUTHORS
JOIN TBL_BOOKS ON TBL_AUTHORS.Author_ID = TBL_BOOKS.Author_ID
ORDER BY TBL_BOOKS.Title ASC;';
This query assumes that each book was published.
SELECT
*
FROM
TBL_Books b
INNER JOIN TBL_Publishers p ON b.Publisher_ID = p.Publisher_ID
INNER JOIN TBL_Authors a ON b.Author_ID = a.Author_ID
ORDER BY
b.Title
Book will always have an Author, but not necessarily a Publisher, if it's not published. If you need to fetch all the books irrespective of whether published or not, you will have to change INNER join on TBL_Publishers to LEFT.
This Query Will show you the result of all details of book, publisher name, author name.
SELECT
t1.* , t2.Publisher_Name , t3.Author_Name
FROM
TBL_Books as t1
INNER JOIN TBL_Publishers as t2 ON t1.Publisher_ID = t2.Publisher_ID
INNER JOIN TBL_Authors as t3 ON t1.Author_ID = t2.Author_ID
ORDER BY
t1.Title
Check This and update if this query helps you.

Most efficient way to perform query

My goal is to get all records from tables where foreign key values match with IDs returned by a subquery from another table.
I have tried several combinations of but they don't even compile.
To clarify, consider following query:
SELECT *
FROM `news`
WHERE IDFIRM IN (SELECT ID FROM firm WHERE Block=0)
AND Actual=1
This is a simple query, but besides the ID in this subquery, I need to also retrieve other columns and return them in response.
Something like this (but of course this doesn't work):
SELECT news.*, sub.name
FROM `news`,
(SELECT * FROM firm WHERE Block=0) AS sub
WHERE news.IDFIRM IN (SELECT sub.ID FROM sub)
AND news.Actual=1
I have an idea how to implement this using joins, but the problem is that there can be multiple IN statements (from different tables), like this:
SELECT *
FROM `news`
WHERE IDFIRM IN (SELECT ID FROM firm WHERE Block=0)
AND Actual=1
AND id_publisher IN (SELECT ID FROM publisher WHERE Block=0)
So this query can become quite different, depending on the request.
How can I create the most efficient query to solve this task? Or it is possible only with multiple queries?
Thanks.
You should definitely use JOIN instead of IN (SELECT ...):
Query 1:
SELECT *
FROM `news`
WHERE IDFIRM IN (SELECT ID FROM firm WHERE Block=0)
AND Actual=1
Replace this by:
SELECT news.*
FROM news
INNER JOIN form ON news.IDFIRM = form.ID
WHERE news.Actual=1
Query 2:
SELECT news.*, sub.name
FROM `news`,
(SELECT * FROM firm WHERE Block=0) AS sub
WHERE news.IDFIRM IN (SELECT sub.ID FROM sub)
AND news.Actual=1
Replace by:
SELECT news.*,
firm.name
FROM news
INNER JOIN firm ON news.IDFIRM = firm.ID
WHERE news.Actual=1
AND firm.Block=0
Query 3:
SELECT *
FROM `news`
WHERE IDFIRM IN (SELECT ID FROM firm WHERE Block=0)
AND Actual=1
AND id_publisher IN (SELECT ID FROM publisher WHERE Block=0)
Replace by:
SELECT news.*
FROM news
INNER JOIN firm ON news.IDFIRM = firm.ID
INNER JOIN publisher ON news.id_publisher = publisher.ID
WHERE news.Actual=1
AND firm.Block=0
AND publisher.Block=0
Adding tables and conditions
So the idea is that you add all the tables you need with clauses like this:
INNER JOIN table1 ON news.<foreign-key> = table1.ID
and that you add the conditions all in the WHEREclause, like this:
WHERE table1.field = <literal>
AND table2.field = <other literal>
AND ...
Assuming your your indexes are sane on both sides of the JOIN they will actually be leveraged, whereas subqueries might use one side.
SELECT [column_list]
FROM news n
INNER JOIN firm f
ON n.idfirm = f.id
INNER JOIN publisher p
ON n.idpublisher = p.id
WHERE n.actual = 1
AND f.block = 0
AND p.block = 0
You are already suggesting a JOIN.
You can use multiple JOIN's to get what you want.
SELECT * FROM news
JOIN firm ON IDFIRM = firm.ID
WHERE Block = 0
JOIN publisher ON id_publisher = publisher.ID
WHERE Block = 0
I'm doing this from memory but should get you close I think.

Joins from same table

I am trying to join the same table "travel_plan" twice, as the value(s) I need are location_from & location_to in which I can then join the value to my cities table to grab the city name.
SELECT * FROM travel_plan
LEFT JOIN Cities ON Cities.CityID = travel_plan.location_to AS plan_to
LEFT JOIN Cities ON Cities.CityID = travel_plan.location_from AS plan_from
LEFT JOIN user_table ON travel_plan.user_id = user_table.id
ORDER BY date_from DESC LIMIT 0,4") or die(mysql_error());
You need to use table aliases correctly when you're joining the same table more than once, as you're doing with Cities in this query.
SELECT *
FROM travel_plan AS tr
LEFT JOIN Cities AS C1 ON C1.CityID = tr.location_to
LEFT JOIN Cities AS C2 ON C2.CityID = tr.location_from
LEFT JOIN user_table AS us ON tr.user_id = us.id
ORDER BY date_from DESC
LIMIT 0,4
The way you wrote your query, the LEFT JOIN AS clauses were misplaced and not used for qualifying the column names.
This use of SELECT * is really suboptimal, however. From this four-table JOIN, SELECT * kicks back lots of columns with duplicate names, which fouls up _fetch_assoc() methods in php.
Your best bet is to enumerate the columns you fetch, and provide aliases so they don't end up with the same names. I don't know the names of your columns so I have to guess, but it would go something like this.
SELECT us.name, us.id AS userid,
C1.cityname AS to_cityname,
C2.cityname AS from_cityname,
FROM ....
Then you'll find the values in $result['from_cityname'] after you fetch each row.
You misuse the AS keyword, it can be only used in the select part of the query (before FROM), or optionally as alias for table references. But not in the ON part of a join. I guess what you want is:
SELECT *, c1.City as toCity, c2.City as fromCity FROM travel_plan LEFT JOIN Cities c1 ON c1.CityID = travel_plan.location_to LEFT JOIN Cities c2 ON c2.CityID = travel_plan.location_from LEFT JOIN user_table ON travel_plan.user_id = user_table.id ORDER BY date_from DESC LIMIT 0,4
Now you can access the the column aliases toCity and fromCity in your resultset, even though the the original column names are the same.

List comments by number of likes

I'm trying to get PHP to list out comments by descending number of likes they receive.
Currently, the comments' content and the number of likes they receive are in 2 separate tables: "comments" and "likes".
PHP code:
To get comments from "comments" table:
$this->db->order_by ('comment_id', 'asc');
$data['comment'] = $this->db->select()->get('comment');
To get likes from "likes" table:
$data['like'] = $this->db->get('like');
To show the number of likes for each comment:
$query_like=$this->db->query("select ip from like where comment_id='$comment_id'");
$count_like=$query_like->num_rows();
I'm wondering if it's possible to order the comments by the number of likes they receive without changing the tables' structure. Any advice hugely appreciated.
If I understand the data structure correctly, you just need a join and an aggregation:
select c.*, count(*) as numlikes
from comments c join
upvote l
on c.comment_id = l.comment_id
group by c.comment_id
order by count(*) desc;
EDIT:
To get comments with zero upvotes, do the left outer join in the other direction:
SELECT c.*, count(u.comment_id) as num_upvotes
FROM comment c left join
upvote u
on c.comment_id = u.comment_id
WHERE c.comment_id = '$interview_id'
GROUP BY c.comment_id
ORDER BY num_upvotes DESC;

Codeigniter 2.1 - join two tables and count in the same query

I have two tables:
news ->
id_news
title
body
date_created
image
category_id
comments ->
id_comments
news_id
body
date_created
How can I write query to get all news, count all the comments for every news and present that query in the view part?
select
N.ID_News,
N.Title,
N.Body,
N.Date_Created,
N.Image,
N.Category_ID,
count(C.ID_Comments) CommentCount
from
News N
LEFT JOIN Comments C
on N.ID_News = C.News_ID
group by
N.ID_News
order by
whatever column(s) are important to you
Since we are counting, we need to make a minor change to DRap's Query:
select
N.ID_News,
N.Title,
N.Body,
N.Date_Created,
N.Image,
N.Category_ID,
count(C.ID_Comments) CommentCount
from
News N
LEFT JOIN Comments C
on N.ID_News = C.News_ID
order by
whatever column(s) are important to you
That will only give you only one result.. as that query lacks a group by statement, I would recommend changing that query to this:
select
N.ID_News,
N.Title,
N.Body,
N.Date_Created,
N.Image,
N.Category_ID,
count(C.ID_Comments) CommentCount
from
News N
LEFT JOIN Comments C
on N.ID_News = C.News_ID
group by
N.title
order by
whatever column(s) are important to you
Writing this down in the Active Record format stays something like this:
$this->db->select('N.ID_News, N.Title, N.Body, N.Date_Created, N.Image')
$this->db->select('N.Category_ID, count(C.ID_Comments) AS CommentCount');
$this->db->from('News AS N');
$this->db->join('commentas AS C', 'N.ID_News = C.News_ID', 'left');
$this->db->group_by('N.title');
After this you can use the order by funtion, to order the resultsas you seefit.

Categories