I have a database with 3 tables with content and i need to get content out of it based on a query of tags.
The tables look like this:
nv_entries:
id - title - year - etc..
nv_tags:
id - entrieid - tag
nv_images:
id - entrieid - source
Let's say i want all entries that have the tag 'rousseau' and both 'fuzz' in it.
After that the images should join aswell where entrieid = entrieid.
This can probably done with one query but i have no idea how.
$query = "SELECT * from nv_entries WHERE ???
please help
Since you have a one to many relationship between entries and tags, you have to use a pivot table on the tags table. Simply saying where tag = 'x" and tag = 'y" won't work because the engine looks at this on a row by row basis so tag can't have both values at the same time. So basically you pivot, assigning flags to each entry that state whether that entry has been seen to have the tag value you're looking for.
SELECT *
FROM nv_entries entries
JOIN (
SELECT entrieid,
COUNT(CASE WHEN (tag = 'rousseau') THEN 1 ELSE null END) has_rousseau,
COUNT(CASE WHEN (tag = 'fuzz') THEN 1 ELSE null END) has_fuzz
FROM nv_tags
GROUP BY entrieid
HAVING has_rousseau != 0 and has_fuzz != 0
) tags ON (entries.id = tags.entrieid)
JOIN nv_images images ON (tags.entrieid = images.entrieid);
SELECT * FROM
nv_entries entries
INNER JOIN nv_tags tags ON tags.entrieid = entries.id
INNER JOIN nv_images imgs ON imgs.entrieid = entries.id
WHERE tags.tag IN('rousseau','fuzz')
but this will extract all data from three tables.
specify your tags relative to the table to avoid redundant tags as entrieid.
Related
I have a few tables:
resources (which contains all the posts)
pid | usrnm | title | link | content | stitle | sdesc | at | likes
tags (which contains all the tags and an ID)
id | slug
retags (which connects the resource and it's tags)
pid | tid
I'm trying to make a search engine with which you can search by multiple tags, a search value and order the results by newest or most liked.
The SQL I use for searching by tags is:
SELECT
resources.pid, resources.title
FROM resources
INNER JOIN retags ON resources.pid = retags.pid
INNER JOIN tags ON retags.tid = tags.id
GROUP BY resources.pid
HAVING
SUM(tags.slug = 'tag-z')
AND
SUM(tags.slug = 'tag-y')
How can I apply the SQL for the search value WHERE title LIKE '%bla%' and order ORDER BY at DESC to this tag search SQL?
I tried select from select but kept gettings errors like "Duplicate column pid", "Column 'pid' in field list is ambiguous" etc
Can someone help me with this SQL? Thanks
I've tried everything in StackOverflow like using an alias for column name on oneSELECT pid as pid_ ... and even on both selects but I still kept getting the same duplicate column error.
EDIT: The SQL I've been getting errors from:
SELECT * FROM
(SELECT * FROM resources
INNER JOIN retags ON resources.pid = retags.pid
INNER JOIN tags ON retags.tid = tags.id
GROUP BY resources.pid
HAVING
SUM(tags.slug = 'A2') AND
SUM(tags.slug = 'AS')
) AS tsr WHERE tsr.title LIKE '%bla%' ORDER BY tsr.`at` DESC
This is just one of them, I've tried a lot of different types from other posts and different errors I get from them.
The WHERE clause goes before the GROUP BY:
SELECT rs.pid, rs.title
FROM resources rs JOIN
retags rt
ON rs.pid = rt.pid JOIN
tags t
ON rt.tid = t.id
WHERE rs.title LIKE '%bla%'
GROUP BY rs.pid
HAVING SUM(t.slug = 'tag-z') AND
SUM(t.slug = 'tag-y')
ORDER BY MAX(rs.at);
Strictly speaking, the MAX() is not needed in the ORDER BY assuming that pid uniquely identifies each row in resources.
My guess is that at is in multiple rows, so you need to qualify the reference with the table it comes from. Note that I introduced table aliases so the query is easier to write and to read.
I have DB with two tables:
rmonth and alternatives
The rmonth is an aggregated table of data for each alternative a complete month - if they have any - otherwise the row don't exist in the rmonth table.
Now I want to join them, and this is my code:
SELECT
COALESCE(rmAntal, 0) AS sumMonth, aID, aText, rmUnitID
FROM
alternatives
LEFT JOIN
rmonth ON aID = rmAltID
WHERE aToQuestID = 4418
AND rmMonth = 3
AND rmYear = 2018
AND rmUnitID IN (10603,10960,10496)
GROUP BY aID, rmUnitID
ORDER BY aID ASC
But it doesn't give me the rows not existing in rmonth.
So this scenario gives me the result as I want it - except that it can't handle where the alternative does not exist for that specific unitID in rmonth.
I want them listed with just 0 in sumMonth.
Unfortunately that's where my MySQL-knowledge is limited.
Thanks.
You could add an OR operator, for example
...
WHERE aToQuestID = 4418 AND rmMonth IS NULL OR (
AND rmMonth = 3
AND rmYear = 2018
AND rmUnitID IN (10603,10960,10496)
)
...
This way, you'll get all your alternatives data, even when it's counter part in rmonth is null.
Just to clarify i can't change the tables structure, so please leave out the "you should change your tables to this and that" answers, thank you.
So i have a table entities_attributes_values where an entity has a lot of attributes and the value of that attribute, basically imagine 3 fields:
entity_id
entity_attributes_id
value
Because every entities attribute and its value is on row getting more values is not so easy i was thinking of multiple self joins, and because this query will be very common i created a view, which is built with this query:
SELECT `L1`.`entity_id`,
`L1`.`value` as 'company_id',
`L2`.`value` as 'entity_name',
`P`.`value` as 'person_name',
`L4`.`value` as 'establishment_id',
`L5`.`value` as 'department_id'
FROM `entities_attributes_values` `L1`
LEFT JOIN `entities_attributes_values` `L2` ON `L1`.`entity_id` = `L2`.`entity_id` AND `L2`.`entity_attributes_id` = 1
LEFT JOIN `entities_attributes_values` `L3` ON `L1`.`entity_id` = `L3`.`entity_id` AND `L3`.`entity_attributes_id` = 3
LEFT JOIN `persons_attributes_values` `P` ON `L3`.`value` = `P`.`core_persons_id` AND `P`.`core_persons_attributes_id` = 4
LEFT JOIN `entities_attributes_values` `L4` ON `L1`.`entity_id` = `L4`.`entity_id` AND `L4`.`entity_attributes_id` = 12
LEFT JOIN `entities_attributes_values` `L5` ON `L1`.`entity_id` = `L5`.`entity_id` AND `L5`.`entity_attributes_id` = 13
WHERE `L1`.`entity_attributes_id` = 2
So this works but i have one problem i get "duplicate" values and its not really duplicate but the point is that in my view i want every entity to be only one row with all its attributes values but instead i get this:
So as you can see the first three result are not good for me, i only need the fourth one, where i have all my data about one entity.
Thank you in advance for any help!
Try using conditional aggregation instead:
select eav.entity_id,
max(case when entity_attributes_id = 2 then eav.value end) as company_id,
max(case when entity_attributes_id = 1 then eav.value end) as entity_name,
max(case when entity_attributes_id = 3 then eav.value end) as company_name,
. . .
from entities_attributes_values eav
group by eav.entity_id;
This will make it easy to add new attributes to the view. Also, don't use single quotes to delimit column names. Single quotes should only be used for date and time constants.
I’m trying to select duplicated nodes on a Drupal site, basically i need to select nodes that share a common ‘tnid' (translation node id), and also share the same ‘language’.
But i can’t figure out how to write the query, i think i did the first part, finding nodes with common tnid, like so
SELECT origin.nid, origin.tnid, origin.title, origin.language
FROM node AS origin
JOIN (select nid, tnid from node
group by tnid having count(tnid) > 1) common_tnid ON common_tnid.tnid = origin.tnid
#JOIN node common_lang ON common_lang.language = origin.language
AND common_lang.tnid = origin.tnid
WHERE origin.tnid != 0
Considering the language part is my big hurdle, how would i add that to the query? I tried a bunch of stuff, thus. the comment.
Try this:
SELECT
table1.nid nid,
table1.tnid tnid,
table1.language language,
table1.title title
FROM
(
SELECT *
FROM
table1
GROUP BY
tnid, language
HAVING
COUNT(*) > 1
) dupe
LEFT JOIN
table1
ON dupe.tnid = table1.tnid
AND dupe.language = table1.language
SQL Fiddle: http://sqlfiddle.com/#!9/294cc/1/0
You can try something like this
SELECT origin.id AS origin_id, common.id AS common_id
FROM node AS origin
INNER JOIN node AS common ON common.language = origin.language AND common.tnid = origin.tnid AND origin.id != common.id
I dont know if your table has id field but you can change to some field that is different in both rows
So firstly here is the relevant table structure:
TUBE_VIDEOS
------
id
video_name
TAGS
----
id
tag_name
tag_type [either set to "actor" or "tag"]
TUBE_VIDEO_TAGS
----
tube_video_id
tag_id
I had asked a question a while back about how to use this data to get related videos: here -- this solution basically took videos with the most common similar tags to decide which were most similar. Since then my database has been modified a bit to show what a tag is describing. So for example "Tom Cruise" is set to tag_type "actor" whereas "explosion" is set to tag_type "tag". What I'd like to do is adjust the query to weigh actors heavier than tags. So essentially we would say to MySQL: Give me a list of video ID's with the most matching actors, in the event of tie use the most matching tags next.
You can do that with just a lot of joins. The following query starts with the current video tv. It looks for all tags belonging to that video tvt. Then it looks for all other video's sharing one or more tags rtvt. For the related video's, it looks up the tag details rt and the video details rtv.
select rtv.video_name
, sum(case when rt.tag_type = 'actor' then 1 else 0 end) ActorCount
, sum(case when rt.tag_type = 'tag' then 1 else 0 end) TagCount
from tube_videos tv
left join tube_video_tags tvt
on tvt.tube_video_id = tv.id
left join tube_video_tags rtvt
on rtvt.tag_id = tvt.tag_id
and rtvt.tube_video_id <> tv.id
left join tags rt
on rt.id = rtvt.tag_id
left join tube_videos rtv
on rtv.id = rtvt.tube_video_id
where tv.id = <YourMovieId>
group by rtv.id, rtv.video_name
order by ActorCount desc, TagCount desc
After all the joins, you can count the various badge types and order by them.