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.
Related
Hopefully i can explain this well enough. I have a bit of a unique issue where the customer system we use can change a ID in the database in the background based on the products status.
What this means is when i want to report old products we don't use anymore along side active products there ID differs between the two key tables depending on there status. This means Active products in the product table match that of the stock item table with both showing as 647107376 but when the product is no long active the StockItem table will present as 647107376 but the table that holds the product information the id presents as -647107376
This is proving problematic for me when i comes to joining the tables together to get the information needed. Originally i had my query set up like this:
SELECT
Company_0.CoaCompanyName
,SopProduct_0.SopStiStockItemCode AS hbpref
,SopProduct_0.SopStiCustomerStockCode AS itemref
,SopProduct_0.SopDescription AS ldesc
,StockMovement_0.StmOriginatingEntityID AS Goodsin
FROM
SBS.PUB.StockItem StockItem_0
LEFT JOIN SBS.PUB.SopProduct SopProduct_0 ON StockItem_0.StockItemID = SopProduct_0.StockItemID
LEFT JOIN SBS.PUB.Company Company_0 ON SopProduct_0.CompanyID = Company_0.CompanyID
LEFT JOIN SBS.PUB.StockMovement StockMovement_0 ON StockItem_0.StockItemID = StockMovement_0.StockItemID
WHERE
Company_0.CoaCompanyName = ?
AND StockMovement_0.MovementTypeID = '173355'
AND StockMovement_0.StmMovementDate >= ? AND StockMovement_0.StmMovementDate <= ?
AND StockMovement_0.StmQty <> 0
AND StockMovement_0.StockTypeID ='12049886'
Unfortunately though what this means is any of the old product will not show because there is no matching id due to the SopProduct table presenting the StockItemID with a leading -
So from this i thought best to use a case when statement with a nested concat and left in it to bring through the results but this doesn't appear to work either sample of the join below:
LEFT JOIN SBS.PUB.SopProduct SopProduct_0 ON (CASE WHEN LEFT(SopProduct_0.StockItemID,1) = "-" THEN CONCAT("-",StockItem_0.StockItemID) ELSE StockItem_0.StockItemID END) = SopProduct_0.StockItemID
Can anyone else think of a way around this issue? I am working with a Progress OpenEdge ODBC.
Numbers look like numbers. If they are, you can use abs():
ON StockItem_0.StockItemID = ABS(SopProduct_0.StockItemID)
Otherwise a relatively simple method is:
ON StockItem_0.StockItemID IN (SopProduct_0.StockItemID, CONCAT('-', SopProduct_0.StockItemID))
Note that non-equality conditions often slow down JOIN operations.
Using an or in the join should work:
LEFT JOIN SBS.PUB.SopProduct SopProduct_0
ON SopProduct_0.StockItemID = StockItem_0.StockItemID
OR
SopProduct_0.StockItemID = CONCAT("-", StockItem_0.StockItemID)
You might need to cast the result of the concat to a number (if the ids are stored as numbers).
Or you could use the abs function too (assuming the ids are numbers):
LEFT JOIN SBS.PUB.SopProduct SopProduct_0
ON SopProduct_0.StockItemID = abs(StockItem_0.StockItemID)
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 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.
I am having some trouble putting a query together. I need to show images pulled in the order of if they are in the "editorial" section then if they have an order to be displayed in it will show the editorial image first but if its not ordered in that section it would just default and pull the regular image that is ordered already (which may not be a editorial type image but is a preferred one if nothing else is available). What I have now is the query below BUT that doesn't pull the editorial ranked images first but rather the "ordered_by' seems to take precedence.
SELECT i.img_name, a.artist_path_name, a.artist_dir, a.artist_name, ck.catKey_id
FROM images AS i JOIN artists AS a USING (artist_id)
JOIN img_cat_table AS imc USING ( img_id )
JOIN catkeys AS ck USING (catKey_id)
WHERE site = 'editorial' AND editorial_order = 1 OR ordered_by = 1 GROUP BY artist_name ORDER BY ed_banner
Its probably something silly that I am missing -- any and all help is appreciated.
Try something like:
...
ORDER BY CASE WHEN site = 'editorial' AND editorial_order = 1 THEN 1 ELSE 2 END,
ed_banner
or the same idea in a simpler way
ORDER BY (site = 'editorial' AND editorial_order = 1) DESC, ed_banner
It simply utilizes the order of FALSE, TRUE.
You should remove the respective conditions from the WHERE clause.
So, I've got a webapp that lets users submit code. The submissions are stored in the code table, and a couple of columns of that are Fulltext-Indexed. This is how I have been performing searches up until now.
But, users can submit their submissions with as many tags as they like - and I'd like these to be included in the search too (but, all in one query...). The tags are stored in the table tags, and there's an intersection table called code_tags that stores the code_id and the tag_id. Standard stuff.
My 'old' search query was this:
SELECT *
FROM code
WHERE MATCH (title, summary, code) AGAINST ('$searchterm')
$searchterm was fetched via PHP $_POST.
So I tried to write a bit more of an 'advanced' query:
SELECT code.*,
code_tags.*,
tags.*,
tags.tag
FROM code, code_tags, tags
WHERE code_tags.code_id = code.id
AND tags.id = code_tags.tag_id
AND MATCH (title, summary, code) AGAINST ('$searchterm')
But all this did was return... nothing. Even when a perfectly valid search term was entered.
So I commented out the last line:
SELECT code.*, code_tags.*, tags.*, tags.tag
FROM code, code_tags, tags
WHERE code_tags.code_id = code.id
AND tags.id = code_tags.tag_id
-- AND MATCH (title, summary, code) AGAINST ('php')
This returns every submission in the database. But, the same row is repeated as many times as there are tags for it (the only difference being, the tag in each returned row).
E.G:
So, finally, I thought I'd be clever and GROUP_CONCAT the tags:
SELECT code.*, code_tags.*, tags.*, GROUP_CONCAT(tags.tag SEPARATOR ' ') AS taggroup
FROM code, code_tags, tags
WHERE code_tags.code_id = code.id
AND tags.id = code_tags.tag_id
-- AND MATCH (title, summary, code, taggroup) AGAINST ('php')`
There are two pretty big problems with this.
With the last AND MATCH line commented out, only one row is returned (with all the details of the first entry in the code table - and taggroup lists every tag, for every submission!
With the last AND MATCH line included, I get the following error: Unknown column 'taggroup' in 'where clause' - damn!
So, what am I meant to do? :S
The reason the following:
SELECT code.*, code_tags.*, tags.*, tags.tag
FROM code, code_tags, tags
WHERE code_tags.code_id = code.id
AND tags.id = code_tags.tag_id
AND MATCH (title, summary, code) AGAINST ('php')
...doesn't return any results is that you don't have any code table records whose title/summary/code match "php" AND have relations to either the CODE_TAGS or TAGS tables. Switching to ANSI-92 JOIN syntax, try:
SELECT c.*, ct.*
FROM CODE c
JOIN CODE_TAGS ct ON ct.code_id = c.id
WHERE MATCH (title, summary, code) AGAINST ('php')
If nothing is returned, then you're problem is that none of the records that satisfy the Full Text Search are related to anything in the CODE_TAGS table -- you'll need to add associations before it will work. That should shine some light on if adding the JOIN to the TAGS table will affect anything:
SELECT c.*, ct.*
FROM CODE c
JOIN CODE_TAGS ct ON ct.code_id = c.id
JOIN TAGS t ON t.id = ct.tag_id
WHERE MATCH (title, summary, code) AGAINST ('php')
Not sure how you can select tags.* and GROUP_CONCAT at the same time but been a while since I was working with MySQL now, anyway join your data in and group by the columns you want should work. Example below.
SELECT code.id, code.title, GROUP_CONCAT(tags.tag SEPARATOR ' ')
FROM code
INNER JOIN code_tags ON code.id = code_tags.code_id
INNER JOIN tags ON code_tags.tag_id = tags.id
WHERE MATCH (code.title, code.summary, code.code) AGAINST ('php')
GROUP BY code.id, code.title