Mysql: pulling from table - mysql

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.

Related

How to ORDER a LEFT JOIN for 2 tables

I've (on reflection ridiculously) stored our 'punters' in 2 tables depending on whether they registered or paid through the express checkout form.
My SQL looks like this:
SELECT
DISTINCT(sale_id), sale_punter_type, sale_comment, sale_refund, sale_timestamp,
punter_surname, punter_firstname,
punter_checkout_surname, punter_checkout_firstname,
punter_compo_surname, punter_compo_firstname,
sale_random, sale_scanned, sale_id
FROM
sale
LEFT JOIN
punter ON punter_id = sale_punter_no
LEFT JOIN
punter_checkout ON punter_checkout_id = sale_punter_no
LEFT JOIN
punter_compo ON punter_compo_id = sale_punter_no
WHERE
sale_event_no = :id
ORDER BY
punter_surname, punter_firstname,
punter_checkout_surname, punter_checkout_firstname
It returns results BUT lists the registered users alphabetically first, then the checkout punters alphabetically.
My question is there a way to get all of the users (registered or checkout) all together sorted alphabetically in 1 sorted list instead of 2 joined sorted lists.
I thought maybe I could use something like punter_checkout_surname AS punter_surname but that didn't work.
Any thoughts? I know now that I shouldn't have used 2 separate tables but but I'm stuck with it now.
Thank you.
I think you just want to use coalesce().
ORDER BY COALESCE(punter_surname, punter_checkout_surname)
COALESCE(punter_firstname, punter_checkout_firstname)
Other comments:
I doubt that DISTINCT is necessary. Why would this generate multiple rows for a single sale_id?
When a query has multiple tables, qualify all the column names (that is, include table aliases so you and others know where the table comes from).
Your data has three sets of names. That seems overkill.
You might want to put the COALESCE() in the SELECT so you don't have quite so many names generated by the query.
Here's my answer:
ORDER BY
COALESCE( UCASE( punter_surname) , UCASE( punter_checkout_surname ), UCASE( punter_compo_surname ) ) ,
COALESCE( UCASE( punter_firstname ) , UCASE( punter_checkout_firstname ), UCASE( punter_compo_firstname) )

Trouble with MySQL query

OK, first-off I admit MySQL Syntax has never been my strongest point. So, here I am.
Urls :
ID Url Code
===============================================
1 http://www.google.com Abcd
2 http://www.freetemplates4u.com Efgh
3 ...
Posts :
ID Title Address
===============================================
1 Some Title 1 http://mize.it/Abcd
2 Some Title 2 http://mize.it/Efgh
3 ...
I want to create a query to fetch the following table
Title Url
=======================================================
Some Title 1 http://www.google.com
Some Title 2 http://www.freetemplates4u.com
In a few words :
Take the Url-Code pairs from Urls table
Search for http://mize.it/+Code in the Posts table (in the Address field)
Combine the final Title and Url in a result table.
I know it has something to do with joins and concatenation, but I'm definitely lost.
SIDENOTE : I don't care neither about my current database's structure, nor about performance issues. All I want is to transfer existing data, from the existing database (without having to alter it), to my new website's database (under a totally different format/structure).
You should change your DB-Design, this query will have a poor performance since mysql has to do a full tablescan.
Try adding a code column in your Posts table hat has the right value (populate it on insert/update) and add an index to Code (both tables).
Now you should be able to do.
SELECT Posts.Title, Urls.Url
FROM Posts
INNER JOIN Urls ON Post.Code = Urls.Code
Update:
If the first part of the url is always the same, this will work
SELECT Post.Title, Urls.Url
FROM Posts
INNER JOIN Urls ON Post.Adress = CONCAT('http://mize.it/', Urls.Code)
TRY
SELECT p.title,x.url
FROM Posts p
INNER JOIN ( SELECT url, CONCAT('http://mize.it/',code) AS xcode FROM Urls ) x
ON (x.xcode = p.address)
Working DEMO
This is a different approch, it took a while for me to test it.
Since your Address field contains complete url and we only need to match what is after / so we can replace actual url with nothing (I assume url is always the same) and have string ready to be matched with Code field.
SELECT b.Title, a.URL
FROM Url a
LEFT JOIN Posts b
ON a.Code = REPLACE(b.Address, 'http://mize.it/', '')
ORDER BY a.ID ASC
Check following query.
select m1.Url, m2.Title from Urls as m1, Posts as m2
where m2.address like 'http://mize.it/%'

Create a last url column from current list of hits

I currently have the following columns:
hit_id, visit_id, timestamp, page_url, page_next
hit_id increments upwards
visit_id is an ID of the visit and unique to each visitor
timestamp is a unix timestamp of the hit
page_url is the page being looked at
page_next is the page that was looked at next
I would like to to add a new column, page_last, where the previous page URL would go into - I should be able to extract this from page_url and page_next. I do not know why I did not create this column in the first place, probably a slight over-site really.
Is there anyway to fill this column using some MySQL trickery? page_last would always be empty on the initial hit on the website (doesn't contain referrer website).
I find the name page_last ambiguous (does it mean the previous page? or this last page on the visit?). I suggest you change it to page_prev.
The following comes close to filling this in, assuming that no one visited the same page multiple times in a visit:
select h.*, hprev.page_url as page_prev
from hits h left outer join
hits hprev
on hprev.page_next = h.page_url and hprev.visit_id = h.visit_id
If that is not true, then you need the most recent one. You can get that using a correlated subquery:
select h.*,
(select h2.page_url
from hits h2
where h2.visit_id = h.visit_id and h2.page_next = h.page_url and
h2.timestamp < h.timestamp
order by timestamp desc
limit 1
) as page_prev
from hits h
Doing the update is a bit tricky in MySQL, because you are not able to directly use the updated table in the update. But, the following trick should work:
update hits
set page_prev = (select page_url
from (select page_url
from hits h2
where h2.visit_id = hits.visit_id and
h2.page_next = hits.page_url and
h2.timestamp < hits.timestamp
order by timestamp desc
limit 1
) h3
)
The trick works because MySQL materializes views, so it actually creates a "temporary table" containing the necessary information for the update.

MYSQL GROUP_CONCAT and IN

I have a little query, it goes like this:
It's slightly more complex than it looks, the only issue is using the output of one subquery as the parameter for an IN clause to generate another. It works to some degree - but it only provides the results from the first id in the "IN" clause. Oddly, if I manually insert the record ids "00003,00004,00005" it does give the proper results.
What I am seeking to do is get second level many to many relationship - basically tour_stops have items, which in turn have images. I am trying to get all the images from all the items to be in a JSON string as 'item_images'. As stated, it runs quickly, but only returns the images from the first related item.
SELECT DISTINCT
tour_stops.record_id,
(SELECT
GROUP_CONCAT( item.record_id ) AS in_item_ids
FROM tour_stop_item
LEFT OUTER JOIN item
ON item.record_id = tour_stop_item.item_id
WHERE tour_stop_item.tour_stops_id = tour_stops.record_id
GROUP BY tour_stops.record_id
) AS rel_items,
(SELECT
CONCAT('[ ',
GROUP_CONCAT(
CONCAT('{ \"record_id\" : \"',record_id,'\",
\"photo_credit\" : \"',photo_credit,'\" }')
)
,' ]')
FROM images
WHERE
images.attached_to IN(rel_items) AND
images.attached_table = 'item'
ORDER BY img_order ASC) AS item_images
FROM tour_stops
WHERE
tour_stops.attached_to_tour = $record_id
ORDER BY tour_stops.stop_order ASC
Both of these below answers I tried, but it did not help. The second example (placing the entire first subquery inside he "IN" statement) not only produced the same results I am already getting, but also increased query time exponentially.
EDIT: I replaced my IN statement with
IN(SELECT item_id FROM tour_stop_item WHERE tour_stops_id = tour_stops.record_id)
and it works, but it brutally slow now. Assuming I have everything indexed correctly, is this the best way to do it?
using group_concat in PHPMYADMIN will show the result as [BLOB - 3B]
GROUP_CONCAT in IN Subquery
Any insights are appreciated. Thanks
I am surprised that you can use rel_items in the subquery.
You might try:
concat(',', images.attached_to, ',') like concat('%,', rel_items, ',%') and
This may or may not be faster. The original version was fast presumably because there are no matches.
Or, you can try to change your in clause. Sometimes, these are poorly optimized:
exists (select 1
from tour_stop_item
where tour_stops_id = tour_stops.record_id and images.attached_to = item_id
)
And then be sure you have an index on tour_stop_item(tour_stops_id, item_id).

Need a hand writing a MySQL query for related videos

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.