I have a 3 tables with the following data in MySQL
tags table
id | groupId | name |
-----------------------------
1 | 1 | tag1 |
2 | 1 | tag2 |
3 | 1 | tag3 |
4 | 1 | tag4 |
groupId column here is unimportant right now.
practice table
id | name |
----------------------
1 | practice 1 |
2 | practice 2 |
3 | practice 3 |
4 | practice 4 |
and a bridge between the two (practiceTag table)
id | practiceId | tagId |
-----------------------------------
1 | 1 | 1 |
2 | 1 | 2 |
3 | 1 | 3 |
4 | 2 | 1 |
But when I try to use the query:
SELECT practice.name
FROM practice
INNER JOIN practiceTag ON practiceTag.practiceId = practice.id
INNER JOIN tags ON practiceTag.tagId = tags.id
WHERE (tags.id = "1"
AND tags.id = "2"
AND tags.id = "3")
it doesn't return anything. And thats ok, since I know my query is kinda messed up. But thats as closest as I can get to show you, what I would like my query to do.
I've searched the forums and find out that I can use a group_concat. But I just can't get it to work.
Any help would be appreciated.
Thanks, Sebastian
I think your tags.id column is integer not string, so your sql query would be like this:
SELECT practice.name
FROM practice
INNER JOIN practiceTag ON practiceTag.practiceId = practice.id
INNER JOIN tags ON practiceTag.tagId = tags.id
WHERE tags.id in (1,2,3);
You in clause not and
SELECT practice.name
FROM practice
INNER JOIN practiceTag ON practiceTag.practiceId = practice.id
INNER JOIN tags ON practiceTag.tagId = tags.id
WHERE tags.id in ( '1', '2', '3') ;
if the id is numeric
SELECT practice.name
FROM practice
INNER JOIN practiceTag ON practiceTag.practiceId = practice.id
INNER JOIN tags ON practiceTag.tagId = tags.id
WHERE tags.id in ( 1, 2, 3) ;
the query is equivalent
SELECT distinct practice.name
FROM practice
INNER JOIN practiceTag ON practiceTag.practiceId = practice.id
INNER JOIN tags ON practiceTag.tagId in (1,2,3)
And if you want only the practice.name when all the 3 tagsId match the you should use temp table for getting the join table
SELECT distinct practice.name
FROM practice
inner join (
select practiceId from
( select distinct practiceTag.practiceId as praticeId, practiceTag.tagId as tagId
from tags ) as t1
where tagId in (1,2,3)
having count(*) > 2
group by praticeId ) as t2;
In your WHERE part you ask for results that have id 1, 2 and 3 at the same time.
Replace the AND in your WHERE with OR
Related
I want to count the number of articles (expected: 2) after grouping by an id but it currently returns only rows with 1 since it counts the occurrences after the GROUP BY.
article:
+-------+---------+
| id | name |
+-------+---------+
| 1 | Apple |
| 2 | Orange |
| 3 | Peaches|
+-------+---------+
article_category:
+---------------+----------------+
| article_id | category_id |
+---------------+----------------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
+---------------+----------------+
Can this be done without a subquery and without using SQL_CALC_FOUND_ROWS? (I'm pretty restricted as I'm using an API endpoint). My only other idea is to simply retrieve all ids and then count them with PHP.
This is my current query:
SELECT COUNT(DISTINCT a.id) as number_articles
FROM article a
INNER JOIN article_category c ON a.id = c.article_id
WHERE c.category_id IN (1, 2, 3)
GROUP BY a.id;
Desired output:
+--------------------+
| number_articles |
+--------------------+
| 2 |
+--------------------+
Here is an SQLFiddle as suggested in the comments: http://sqlfiddle.com/#!9/8b2975/1
Based on the expected result you added now. You can remove the GroupBy, its really not achieving much here, this should work:
select count(distinct a.id)
from article a
INNER JOIN article_category c ON a.id = c.article_id
WHERE c.category_id IN (1, 2, 3)
try below solution.
select count(DISTINCT a.id) as total
from article a
INNER join article_category c on a.id = c.article_id
WHERE category_id in (1,2,3);
RESULT:
total
2
Just count the value of c.category_id instead of a.id
SELECT COUNT(c.category_id) FROM article a INNER JOIN
article_category c ON a.id = c.article_id WHERE c.category_id
IN (1, 2, 3) GROUP BY a.id;
SELECT COUNT(DISTINCT a.id)
FROM article a
INNER JOIN article_category c ON a.id = c.article_id
I have three tables:
person_table
id| name | gender
1 | Joe | male
2 | Jane |female
3 | Janet | female
4| Jay | male
etc...
product_table
id| name
1 | magazine
2 | book
3 |paper
4 | novel
etc...
**person_product
person_id| product_id | quantity
1 | 1 | 1
1 | 3 | 3
2 | 3 | 1
4 | 4 | 2
etc...
I have tried to make a query that will return a table like this:
person_id| person_name | product_name| quantity
but i can't make it so that if lets say John has no books, it should display
(johns id) John|book|0
instead of just skipping this line.
Where did i go wrong?
here is what i managed to come up with:
SELECT p.*, f.name, l.quantity
FROM person_product AS l
INNER JOIN people_table AS p ON l.person_id=p.id
INNER JOIN product_table AS f ON l.product_id=f.id
ORDER BY id`
It seems that you're generating a report of all people, against all products with the relevant quantity; on a large data set this could take a while as you're not specifically joining product to person for anything other than quantity:
SELECT
p.id,
p.name,
p.gender,
f.name,
IFNULL(l.quantity,0) AS quantity
FROM person_table AS p
JOIN product_table AS f
LEFT JOIN person_product AS l
ON l.person_id = p.id
AND l.product_id = f.id
ORDER BY p.id, f.name
Which results in:
Is that more-or-less what you're after?
you need to start with people_table than using left join you need to bring other table data.
as you need 0 value if null than you can use function IFNULL
SELECT p.*, f.name, IFNULL(l.quantity,0)
FROM people_table AS p
LEFT JOIN person_product AS l ON l.person_id=p.id
LEFT JOIN product_table AS f ON l.product_id=f.id
ORDER BY p.id
if has no book shouldn't appear in the table , try this (easy to understand) :
SELECT NAME
,'0'
,'0'
FROM person_table
WHERE id NOT IN (
SELECT person_id
FROM person_product
)
UNION
SELECT person_id
,product_id
,quantity
FROM person_product;
I have this tables :
Table: Articles
id | title | display |
-----------------------------------
1 | Fkekc | 1 |
2 | ldsdf | 1 |
3 | OTRld | 0 |
4 | QCRSA | 1 |
Table: Likes
id | article_id | like | type
----------------------------------------
1 | 1 | 121 | 1
2 | 1 | 652 | 2
3 | 2 | 12 | 1
4 | 1 | 5 | 3
i want get this result:
Article [1] => 778
Article [2] => 12
Article [3] => 0
Article [4] => 0
I use LEFT JOIN between two tables but this return records per likes table. so i get three record of article 1
My code:
SELECT articles.*,likes.like FROM `articles` LEFT JOIN `likes` ON articles.id=likes.article_id WHERE display='1'
I know that i must use SUM() but i didn't know how use it
With your answers i find that i must use this:
SELECT articles.*, sum(likes.like) as likesSum FROM `articles` LEFT JOIN `likes`ON articles.id=likes.article_id WHERE display='1' GROUP BY articles.id
But i want to set filter in query. so use this :
SELECT articles.*, sum(likes.like) as likesSum FROM `articles` LEFT JOIN `likes`ON articles.id=likes.article_id WHERE display='1' && likesSum>='100' GROUP BY articles.id
But above code doesn't return any result
This is your query
SELECT articles.*,COALESCE(sum(likes.like),0) as total_like FROM
`articles` LEFT JOIN `likes` ON articles.id=likes.article_id group by
articles.id
Output is
SELECT articles.*, sum(likes.like) as likesSum FROM `articles` LEFT JOIN `likes`ON articles.id=likes.article_id WHERE display='1' GROUP BY articles.id
This should work for you perfectly..
SELECT articles.id, sum(likes.like) from articles left join likes on (articles.id=likes.article_id) group by articles.id order by articles.id
See the use of SUM() with GROUP BY
This visual representation is great to understand the joins: http://www.codeproject.com/Articles/33052/Visual-Representation-of-SQL-Joins
You did everything right but only one this missing. You should have used group by
SELECT articles.*, likes.like
FROM `articles`
LEFT JOIN `likes` ON articles.id = likes.article_id
WHERE display = '1'
GROUP BY likes.article_id
First, apologies if the title doesn't match the question. Well, the problem is how to build this query...
I have a table called category It contains categories of my stuff(movies). It's like this...
--------------------------------
ID | name | parent_category
--------------------------------
1 | love | 0
2 | action | 0
3 | fear | 0
4 | passion| 1
5 | danger | 2
6 | death | 3
--------------------------------
So, as you see, each category has a parent category. Except the first 3. They're parents.
And movies table is like this...
--------------------------------
ID | name | category
--------------------------------
1 | aaaa | 1
2 | bbbbbb | 2
3 | cccc | 2
4 | ddddddd| 1
5 | eeeeee | 3
6 | fffff | 3
--------------------------------
So, what i want to do is, to select movies by parent category. Which means if I click category, love, it should select all the movies of categories that having love as the parent category.
So, how to write this in a single query ?
If the parents are only one level deep, then you can use joins:
select m.*,
coalesce(cp.id, c.id) as parent_id,
coalesce(cp.name, c.name) as parent_name
from movies m left join
categories c
on m.category = c.id left join
categories cp
on c.parent_category = cp.id;
Actually, if you only want the id, you don't need two joins:
select m.*,
(case when c.parent_id > 0 then c.parent_id else c.id end) as parent_id
from movies m left join
categories c
on m.category = c.id ;
Or, more simply:
select m.*, greatest(c.parent_id, c.id) as parent_id
. . .
to select rows filtered by condition on secend table use join in FROM clause or subquery in condition with IN or EXISTS function. To compare field with some string you can use LIKE operator.
If you are filtering based on parent_category -
SELECT b.*, a.name FROM movies b
LEFT JOIN categories a ON a.id = b.category
WHERE a.parent_category = 1;
I'm creating a site in wordpress which holds information on television programs. I'm using custom fields to select each post.
The table looks something like this
+----+---------+----------+------------+
| id | post_id | meta_key | meta_value |
+----+---------+----------+------------+
| 1 | 1 | name | Smallville |
| 2 | 1 | season | 1 |
| 3 | 1 | episode | 1 |
| 4 | 2 | name | Smallville |
| 5 | 2 | season | 1 |
| 6 | 2 | episode | 2 |
+----+---------+----------+------------+
Basically what I need to do is select all of the tv shows with the name "Smallville" and sort them by season then by episodes. I thought it would be fairly simple but everything I have tried returns nothing.
Could you please explain how I can do this?
You can do something like this:
SELECT
t1.post_id,
t1.meta_value AS name,
t2.meta_value AS season,
t3.meta_value AS episode
FROM
(
SELECT *
FROM the_table
WHERE meta_key = 'name'
) t1
INNER JOIN
(
SELECT *
FROM the_table
WHERE meta_key = 'season'
) t2 ON t1.post_id = t2.post_id
INNER JOIN
(
SELECT *
FROM the_table
WHERE meta_key = 'episode'
) t3 ON t1.post_id = t3.post_id
This will give you the result:
| post_id | name | season | episode |
-------------------------------------------
| 1 | Smallville | 1 | 1 |
| 2 | Smallville | 1 | 2 |
In this form it is much easier for any operations.
What you need is to add:
WHERE name = 'Smallville'
ORDER BY season, episode
Combine the rows using a self-join, and you're good to go:
SELECT *
FROM yourtable name
INNER JOIN yourtable season
on season.post_id = name.post_id
and season.meta_key = 'season'
INNER JOIN yourtable episode
on episode.post_id = name.post_id
and episode.meta_key = 'episode'
WHERE name.meta_key = 'name'
and name.meta_value = 'Smallville'
ORDER BY season.meta_value, episode.meta_value
A more general case: sort-of conversion from your format to a more normal relational DB format:
SELECT (SELECT meta_value FROM data t1 WHERE t1.post_id = t0.post_id AND meta_key = "season") AS season,
(SELECT meta_value FROM data t1 WHERE t1.post_id = t0.post_id AND meta_key = "episode") AS episode
FROM data t0 WHERE meta_key = "name" AND meta_value = "Smallville"
For the actual sorting you can't reuse the season / episode values (those aren't assigned yet while sorting), so you have to copy/paste the subquery into the ORDER BY clause:
ORDER BY (SELECT ... "season") ASC, (SELECT ... "episode") ASC,
No need to do direct SQL.
You've got access to the SQL query through the WP_Query object. Check out the filters surrounding the where clause in the WP_Query object (there is more than 1 way to get at it) and simply modify the default WP_Query parts before they're concatenated together.
Start by setting up a WP_Query object that gets all the posts by postmeta key & postmeta value, and then tack on a bit more to the where clause to do some extra conditionals.
There's another filter that allows you to get at the ordering section of the SQL query so you can modify that.
There's no reason to hand write SQL here, just modify what has already been built for you.
the idea is to join the table to itself 3 times where for each of them take rows for a given meta_key:
SELECT t1.meta_value name, t2.meta_value season, t3.meta_value episode
FROM table t1
JOIN table t2 on t1.post_id = t2.post_id and t2.meta_key = 'season'
JOIN table t3 on t1.post_id = t3.post_id and t3.meta_key = 'episode'
WHERE t1.meta_key = 'name'
AND t1.meta_value = 'Smallville'
ORDER BY t2.meta_value, t3.meta_value