Select multiple tables - mysql

This is a part of my DB structure that I want to query:
The relations are these:
article.art_author - user.usr_id
article.art_id - tag_article.rel_art_id
tag_article.rel_tag_id - tag.tag_id
I want to select the articles that are written from selected users (by usr_id) OR the article that have the selected tags (by tag_id) in one query if possible.
I have tried this but does not give me the desired result:
SELECT * FROM
((article JOIN user on article.art_author = user.usr_id)
JOIN
tag_article on article.art_id = tag_article.rel_art_id)
JOIN
tag on tag_article.rel_tag_id = tag.tag_id
WHERE
article.art_lang = '$cur_lang'
$sql_in
ORDER BY
article.art_date desc
LIMIT $first_record, $range

select distinct a.art_id
from article a,
user u,
tag_article ta,
tag t
where a.art_author=u.user_id
and ta.rel_art_id = a.art_id
and ta.rel_tag_id = t.tag_id
and (u.usr_id in (<your selected users>) or t.tag_id in (<your selected tag>))
I wrote all joints so you can select all columns you want, but it can be done more rapidly if you just need article data :
select a.art_id
from article a,
tag_article ta
where a.art_id=ta.rel_art_id
and (a.art_author in (<your selected users>) or ta.rel_tag_id in (<your selected tags>))

Related

Select rows with same id that have other data ( search )

I'm trying to build a search function but the current table structure troubles me.
So each row identifies a 'tag' association with an audio ID.
TABLE audio_tag_assoc example
I get the name of each tag id by joining the table tag_association.
TABLE tag_association example
Therefore I need to get all the audio ids that match two or even three tag names.
What I tried is the following but you can probably tell that it doesn't work. I would have later added a join in between those parentheses to change the IDs of the IN with strings.
SELECT *
FROM audio_tag_assoc a
JOIN tag_association b ON a.tag = b.id
WHERE a.audio = (SELECT *
FROM audio_tag_assoc
WHERE tag IN (2,3)
)
Initially I tried having b.name = 'Male' AND b.name = 'Film' but of course, that's not how mysql WHERE clause works.
Do :
SELECT
*
FROM
audio_tag_assoc
INNER JOIN
tag_association ON audio_tag_assoc.tag = tag_association.id
WHERE
audio_tag_assoc.id IN (SELECT
a.id
FROM audio_tag_assoc a
WHERE
a.tag IN (2,3)
GROUP BY
a.audio
HAVING COUNT(a.id) >= 2
);

to write a select query which strictly satisfies a multiple condition on same column

I want to write a select query by joining two tables.
like this..
select entityid from companytagrel left join taginfo on companytagrel.tagid=taginfo.tagid where taginfo.tag = "own" and taginfo.tag ="rocking";
where the relationship between tables companytagrel and taginfo are N->1
i want to select the entityid which strictly satisfy the condition that its taginfo.tag is own and rocking.
note: A company can have any number of tags.
companytagrel's column->(uniqueid,entityid,tagid)
taginfo's column -> (tagid,tagname)
You can do this using group by and having:
select ct.entityid
from companytagrel ct left join
taginfo t
on ct.tagid = t.tagid
where t.tag in ('own', 'rocking')
group by ct.entityid
having count(distinct t.tag) = 2;

How can I use a join to combine these two queries?

I have two tables: articles and modifications. I want users to easily be able to revert their article back to it's original state if they realize they shouldn't have modified it. Instead of using an extra query to find the id of the article's newest modification, I would like to use a join. So I want to get the information from the articles table and then join the modifications table to it to return the associated row. This is what I have now:
<?php
$query = "
SELECT
article_id, title, content
FROM articles
WHERE article_id = ".$article_id."
LIMIT 1";
$query_article = $this->db->query($query);
$article = $query_article->row_array();
$query_mod = "
SELECT
modification_id, article_id, title, content, date
FROM modifications
WHERE article_id = ".$article_id."
ORDER BY modification_id DESC
LIMIT 1";
$query_mod = $this->db->query($query);
if($query_mod->num_rows() > 0){
$mod = $query_mod->row_array();
$article_title = $mod['title'];
$article_content = $mod['content'];
} else {
$article_title = $article['title'];
$article_content = $article['content'];
}
How could I combine these two queries into one using a join?
SELECT
a.title, a.content, a.article_id
m.modification_id AS mod_id, m.title AS mod_title, m.content AS mod_content
FROM articles AS a
LEFT JOIN modifications AS m ON (...)
WHERE a.article_id = 1
LIMIT 1
Your skeletal attempt at a query is pretty much correct except for the empty ON clause, which merely needs to identify equality between article_id on the two tables. It is correct to use a LEFT JOIN since you need to return the article regardless of a match in modifications.
SELECT
a.title, a.content, a.article_id,
m.modification_id AS mod_id, m.title AS mod_title, m.content AS mod_content
FROM
articles AS a
LEFT JOIN modifications AS m ON a.article_id = m.article_id
WHERE a.article_id = 1
ORDER BY mod_id DESC LIMIT 1
However, your PHP logic shows that you are conditionally using the title,content from the modifications table if it is present. For that, you may use COALESCE() directly in the SQL to return the first non-null argument, so if the LEFT JOIN has no match, article will be used.
SELECT
-- COALESCE to prefer the modifications value if non-null
COALESCE(m.title,a.title) AS title,
COALESCE(m.content, a.content) AS content,
a.article_id,
m.modification_id AS mod_id
FROM
articles AS a
LEFT JOIN modifications AS m ON a.article_id = m.article_id
WHERE a.article_id = 1
ORDER BY mod_id DESC LIMIT 1
Here's a demonstration: http://sqlfiddle.com/#!2/1085c/1
Because you're only attempting to return details for one article_id, no subqueries are needed. This gets a little more complicated if you want to return the latest for multiple article_id, requiring a subquery join with a MAX() aggregate.
SELECT
COALESCE(m.title,a.title) AS title,
COALESCE(m.content, a.content) AS content,
a.article_id,
m.modification_id AS mod_id
FROM
articles AS a
-- Join articles against a subquery to get the most recent mod_id only
LEFT JOIN (
SELECT article_id, MAX(modification_id) AS mod_id
FROM modifications
GROUP BY article_id
) mm ON mm.article_id = a.article_id
-- and then join that mod_id against the rest of the modifications table
LEFT JOIN modifications m ON mm.mod_id = m.modification_id
WHERE article_id IN (<multiple criteria for article_id>)
http://sqlfiddle.com/#!2/14051/2

Select parents based on all children statisfying condition

This is such a simple problem but for some reason I cannot get my head round it today.
I have two entities:- title and product each respectively named tbl_title and tbl_product. Each title can have many products.
The product table has a field called unwanted which can be either null, 0 or 1.
I wish to select all titles based on where all products (ALL) have unwanted set to 1. So in other words I wish to select the parent based upon all children filling a certain condition. So if a title has one product that is unwanted but another that is not I do not wish for this title to enter the result set.
When I try this the most I get out of my head is:
SELECT * FROM `tbl_title`
left join tbl_product on tbl_product.title_id = tbl_title.id
where tbl_product.unwanted = 1
group by tbl_title.id
Which obviously does not work.
So how do I code such a query?
select * from tbl_title
where id not in (select title_id from tbl_product where unwanted = 0)
In English, this query eliminates all titles that have a wanted product.
From a style point of view, it would be better to call your column wanted, because unwanted = 0 is a double-negative of wanted = 1. It's always easier to get your head around positives.
SELECT t.id
FROM `tbl_title` t
left join tbl_product p on p.title_id = t.id
group by t.id
having sum(p.unwanted = 0 or p.unwanted is null) = 0
Try using a subquery like this:
SELECT * FROM `tbl_title` AS t
WHERE EXISTS (SELECT 1 FROM products WHERE title_id = t.id AND unwanted = 1)
AND NOT EXISTS (SELECT 1 FROM products WHERE title_id = t.id AND (unwanted = 0 OR unwanted IS NULL))
Just for the fields in title table
SELECT *
FROM `tbl_title` AS t
JOIN tbl_product AS v ON t.id = v.title_id
WHERE NOT EXISTS(
SELECT *
FROM tbl_product
WHERE (t.id = title_id)
AND (unwanted = 0 OR unwanted IS NULL)
GROUP BY t.id

mysql join with limit 1

Suppose I have two tables in one to many relationship.
And, I want to select columns from each main record along with the first record from a related table.
I tried some ways but it just doesn't go...
Here I end up with this SQL fiddle:
http://sqlfiddle.com/#!2/39fdb/3
The problem there is that it just cannot reference a.ID from a subselect.
This does not work, of course, but it's just all I could think of
select a.*,b.* from event a left join
(select * from event_pictures where a.ID=article limit 1)
b on a.ID=b.article;
Any ideas on how to fix it?
No, you can't reference a.ID in a subselect that is joined to a. You can do the following, but you better supply an ordering. Otherwise, there is no "first" row. A (more or less) random row from table b will be selected:
select a.*, b.*
from event a
left join event_pictures b
on b.PK = --- the PRIMARY KEY
( select bb.PK --- of event_pictures
from event_pictures bb
where a.ID = bb.article
ORDER BY bb.something
limit 1
) ;
If you don't care which image gets returned for an article, you can select the MIN or MAX image grouped by article (rather than doing a LIMIT 1) in your subquery
SQL Fiddle
You could use min or max as suggested already:
select
e.*,
(
select min(ep.img)
from event_pictures as ep
where ep2.article = e.article
) as img
from
event as e
If you want img based on highest ID:
select
e.*,
(
select ep2.img
from event_pictures as ep2
where ep2.ID = last_ep.last_ID
) as img
from
event as e inner join -- could be a left join if necessary
(
select ep.article, max(ep.ID) as last_ID
from event_pictures as ep
group by ep.article
) as last_ep
on last_ep.article = e.ID
Neither approach requires the use of limit.
Here is one way to do it:
select e.*, ep.*
from (select e.*,
(select article
from event_pictures ep
where ep.article = e.id
order by rand()
limit 1
) as eparticle
from event e
) e left join
event_pictures ep
on e.eparticle = ep.article
The subquery finds one randome "article". The information for this is then joined in.