SQL index/relation - php

I'm indexing two things of posts. One is the title (words) and two are the keywords. I've chosen to use 3 tables for this:
word_index (word,word_id) // al words and keywords are indexed
keyword_rel (word_id,postId) // relations with the keywords
word_rel (word_id,postId) // relations with the the words of the title
Now I'm trying to perform a decent search query on this. Using the keywords only, it works fine.
SELECT p.postId
FROM word_index wi
INNER JOIN keyword_rel kr ON wi.word_id=kr.word_id
INNER JOIN post p ON p.postId=kr.postId
WHERE wi.word LIKE 'input%'
GROUP BY p.postId
But now I would like to include word_rel to also search in the title.
I tried this, but it doesn't sound right and also doesn't return everything (missing some of wi.word):
SELECT p.postId,wi.word
FROM word_index wi
INNER JOIN keyword_rel kr ON wi.word_id=kr.word_id
INNER JOIN word_rel wr ON wi.word_id = wr.word_id
INNER JOIN post p ON p.postId=kr.postId
INNER JOIN post pi ON pi.postId=wr.postId
WHERE wi.word LIKE 'input%'
GROUP BY p.postId
The problem is with INNER JOIN post p which is related to keyword_rel. Now I also need it related to word_rel. What is a good way to do this ?

You would need to do a UNION here:
SELECT p.postId, wi.word
FROM word_index wi
INNER JOIN keyword_rel kr ON wi.word_id = kr.word_id
INNER JOIN post p ON p.postId=kr.postId
WHERE wi.word LIKE 'input%'
GROUP BY p.postId
UNION
SELECT p.postId, wi.word
FROM word_index wi
INNER JOIN word_rel wr ON wi.word_id = wr.word_id
INNER JOIN post p ON p.postId=wr.postId
WHERE wi.word LIKE 'input%'
GROUP BY p.postId
And since this may return some of the results twice or more times (especially if the word is contained in both keywords and titles), You may want to wrap the above query into another SELECT DISTINCT:
SELECT DISTINCT t.post_id, t.word
FROM (
SELECT ...
UNION
SELECT
) t
ORDER BY t.word ASC

Related

is there a way of joining two tables with the clause, "inner join," then followed by multiple "left join" clause

i'm setting up mysql query against four table, i want the result of the left not to have effect on the query of the inner join. what am i do wrong? forgive my naivety
the problem here is that when i remove the two left join in the query i get eight results as expected but with the left join in the query i get only one result even when there're more products in the product table.
$this->getAllRecords("SELECT t.content_type_name as type,
p.title,p.start_date, p.end_date, p.last_enroll_date,
p.seat, p.cost, p.description, COUNT(r.stars) as review_count,
AVG(r.stars) as stars, i.image, p.location
FROM content_type t
INNER JOIN product p ON t.content_type_id=c.content_type_id
LEFT JOIN product_review r ON p.product_id=r.product_id
LEFT JOIN image i ON p.uid=i.reference_page_or_product
AND p.active=1
ORDER BY RAND()
LIMIT 8"))
i want all product whether there are reviews and image or not
You are using aggreation function withou group by and this could produce unpredictable result (probaly you are using a mysql db version preceding 5.7)
The aggredated result could be related to null value and this also can reduce/omit the result
You should use group by for aggreation function and use a subquery for obtain the related valid result .. and use the subqiery for left join
SELECT t.content_type_name as type
, p.title,p.start_date
, p.end_date
, p.last_enroll_date
, p.seat
, p.cost
, p.description
, p.location
, i.image
, t.review_count
, t.stars
FROM content_type t
INNER JOIN product p ON t.content_type_id=c.content_type_id
AND p.active=1
LEFT JOIN (
SELECT r.product_id
, COUNT(r.stars) as review_count
, AVG(r.stars) as stars
FROM product_review r
GROUP BY r.product_id
) t ON ON p.product_id=t.product_id
LEFT JOIN image i ON p.uid=i.reference_page_or_product
ORDER BY RAND()
LIMIT 8
For better view The p.active=1 should be assigned to the on clause for product
See this page for proper nesting of joins, and use of parathesis: https://dev.mysql.com/doc/refman/8.0/en/nested-join-optimization.html
but there is a bug in the SQL, which should be expressed as WHERE:
SELECT t.content_type_name as type, p.title,p.start_date, p.end_date, p.last_enroll_date,
p.seat, p.cost, p.description, COUNT(r.stars) as review_count,
AVG(r.stars) as stars, i.image, p.location
FROM content_type t
INNER JOIN product p ON t.content_type_id=c.content_type_id
LEFT JOIN product_review r ON p.product_id=r.product_id
LEFT JOIN image i ON p.uid=i.reference_page_or_product
AND p.active=1
ORDER BY RAND()

Group by and count data with one query

This is my table structure in database
I want to get number of likes for each post by counting post field in likes table and display it for every post using foreach loop.
My question is
Is there a way i can do this with one query with JOIN, GROUP BY and COUNT tables and not create multiple queries.
select p.id, p.title, p.content, count(l.id) as likes_count
from posts p
left join likes l on l.post = p.id
group by p.id, p.title, p.content
http://sqlfiddle.com/#!9/bca8ee/1
SELECT p.*, COUNT(l.id)
FROM posts p
LEFT JOIN likes l
ON l.post = p.id
GROUP BY p.id

How to get individual count of same value rows with join

I just want to know how to get individual count of same value rows with join using mysql and help are definitely appreciated
Here is my mysql Query
SELECT c.`id`
FROM categories c inner join subcategories sc
on c.`id` = sc.`cat_id`
See the Response screeshot
try this query:
SELECT c.`id`, count(1)
FROM categories c inner join subcategories sc
on c.`id` = sc.`cat_id`
GROUP BY c.`id`
It's quite a basic task. Consider studying GROUP BY and aggregate functions.
SELECT id, COUNT(*)
FROM categories c
INNER JOIN subcategories sn ON c.id = sn.cat_id
GROUP BY c.id

Is there an alternative for MYSQL HAVING

I'm trying to find some records based on the tags they have. In order to find out which tags a record has i add them to the result using a subquery. To find out which results should be returned i added a having statement on the end of the query. But something tells me this is not the best way.
SELECT e.id, e.title, e.text, e.introduction,
UNIX_TIMESTAMP(e.starts_on) AS starts_on,
UNIX_TIMESTAMP(e.ends_on) AS ends_on,
m.id AS meta_id,
m.url,
cm.title AS category_title,
cm.url AS category_url,
CONCAT(
",",
(
SELECT GROUP_CONCAT(t.id)
FROM modules_tags AS mt
JOIN tags AS t ON t.id = mt.tag_id
WHERE mt.other_id = e.id
),","
) AS tags_search
FROM event_posts AS e
INNER JOIN meta AS m ON e.meta_id = m.id
LEFT JOIN event_categories AS c ON e.category_id = c.id
LEFT JOIN meta AS cm ON c.meta_id = cm.id
LEFT JOIN modules_tags AS mt ON mt.other_id = e.id
LEFT JOIN tags AS t ON t.id = mt.tag_id
WHERE 1 HAVING tags_search LIKE '%,5,%' AND tags_search LIKE '%,6,%'
FIND_IN_SET() is the best way to find values in comma separated values in MySQL.

How to query 3 tables in a single query?

I'm really sorry for the first post as i didn't explain everything.
Basically i have 3 tables, One for posts, One for Categories, & Another to link categories with posts.
I want in a single MySQL query to select posts that are under a specific category.
posts(id,title,body)
---------------------
125,Some title,Blah blah
categories(id,name)
---------------------
1,politic
2,entertainment
linker(categoryid,postid)
---------------------
2,125
I want in single query to fetch posts in the entertainment category by example, what to do?
Thanks
select
p.*
from
posts p
inner join linker l on l.postid = p.id
inner join categories c on c.categoryid = l.categoryid
where
c.name = 'entertainment'
The following SQL statement should provide you with a basis for what you are trying to do.
select p.*
from posts p
inner join linker l
on l.postid = p.id
inner join categories c
on l.categoryid = c.id
where c.name = 'entertainment'
If a post belongs to 2 categories, you can still use pinkfloydx33's query with DISTINCT in the select statement:
select
DISTINCT p.*
from
posts p
inner join linker l on l.postid = p.id
inner join categories c on c.categoryid = l.categoryid
where
c.name = 'entertainment'
The result set will show only one record.
It's the same exact thing, you just have to join 3 tables intead of 2 :
SELECT P.id post_id,
P.title,
P.body,
C.id category_id,
C.name
FROM posts P
INNER JOIN linker L
ON P.id = L.postid
INNER JOIN categories C
ON L.categoryid = C.id
WHERE C.name = 'Category'
Don't be afraid to do your own tests. If you understand how to join two tables, you should understand how to join three, four and more.
If you are specifying only one category in the WHERE clause, then the result will be a single row for each post ID.
Either way you can use DISTINCT or GROUP BY when the result could be more than one row per ID, but in that case i prefer the second one (GROUP BY).

Categories