MySQL user variable addition: '+1' return '+2' - mysql

I'm coding a movie search engine called Movieovo, I want to select the top 5 rows (movie links) from each group (movie title), but I met a problem in this SQL query:
SELECT link_movie_id, link_id,
#num := if(#link_movie_id = link_movie_id, #num + 1, 1) as row_number,
#link_movie_id := link_movie_id as dummy
FROM link GROUP BY link_movie_id, link_id HAVING row_number <= 5 LIMIT 30
Result: ( Too many characters so I upload as an image )
http://i.imgur.com/phFzUF1.png
You can see "row_number" does not +1 each time
I tried directly in MySQL command line shows me the same results, can anyone help me? I have already wasted 5 hours in this problem..

You are incrementing link_movie_id by 1, but you are grouping by link_movie_id and link_id. With the effect, for some link_movie_id, there are multiple values of link_id in the result. If you are want to get what you are looking for, either group by a single field, or increment it based on a concatenated combination of link_movie_id and link_id.

Related

How do i make duplicates in a existing column unique?

I am using MySQL 5.6 Server. I use Navicat to work in the DB.
I have searched and found alot of possible solutions to my problem but none of them have worked for me.
I have a table with around 36000 rows. I have a column wich allowes duplicate entrys but i would like to make the duplicates in the row unique. Column with duplicates
I can find my duplicates using this query.
But there is to many to manually edit them all. Search Result
SELECT name, COUNT(ItemTemplate_ID)
FROM itemtemplate
GROUP BY ItemTemplate_ID
HAVING ( COUNT(ItemTemplate_ID) > 1 )
What i am looking for is a way to do one of these things.
Update the duplicates with new unique entries.
Add a text entry in another column for every duplicates. (I have a couple of empty columns i can use to add some text too.
Update the entire column with unique entries. ( Doesnt matter what its calle just has to be unique.)
Thanks in advance.
Edit - There allready is a unique column called Id_nb.
The column i want to change entries in should not be unique.
Let me assume that you do not have a unique column in the table. If so, you can do this with variables:
set #rn := 0;
set #it := '';
update itemtemplate it
set it.ItemTemplate_ID = (case when #it = it.ItemTemplate_ID
then concat_ws('_', it.name, (#rn := #rn + 1))
when #it := it.ItemTemplate_ID
then if(#rn := 0, it.ItemTemplate_ID, it.ItemTemplate_ID)
else if(#rn := 0, it.ItemTemplate_ID, it.ItemTemplate_ID)
end)
order by it.ItemTemplate_ID;
This method does assume that there are not already columns with names like "ABC" and "ABC_1".
Update the duplicates with new unique entries.
Let's assume that you have a unique column named id.
update itemtemplate set ItemTemplate_ID = (select md5(uuid())) where
FIND_IN_SET(id,(SELECT GROUP_CONCAT(id) FROM itemtemplate GROUP BY ItemTemplate_ID HAVING ( COUNT(ItemTemplate_ID) > 1 ) ));
Add a text entry in another column for every duplicates. (I have a couple of empty columns i can use to add some text too.
update itemtemplate set ItemTemplate_ID = (select md5(uuid())), emptyColumn='text' where
FIND_IN_SET(id,(SELECT GROUP_CONCAT(id) FROM itemtemplate GROUP BY ItemTemplate_ID HAVING ( COUNT(ItemTemplate_ID) > 1 ) ));
Sorry, I don't quite understand the third question.
By the way,if you have executed the first sql, the second sql will not work anymore.

Getting previous row in MySQL

I'm stucked in a MySQL problem that I was not able to find a solution yet. I have the following query that brings to me the month-year and the number new users of each period in my platform:
select
u.period ,
u.count_new as new_users
from
(select DATE_FORMAT(u.registration_date,'%Y-%m') as period, count(distinct u.id) as count_new from users u group by DATE_FORMAT(u.registration_date,'%Y-%m')) u
order by period desc;
The result is the table:
period,new_users
2016-10,103699
2016-09,149001
2016-08,169841
2016-07,150672
2016-06,148920
2016-05,160206
2016-04,147715
2016-03,173394
2016-02,157743
2016-01,173013
So, I need to calculate for each month-year the difference between the period and the last month-year. I need a result table like this:
period,new_users
2016-10,calculate(103699 - 149001)
2016-09,calculate(149001- 169841)
2016-08,calculate(169841- 150672)
2016-07,So on...
2016-06,...
2016-05,...
2016-04,...
2016-03,...
2016-02,...
2016-01,...
Any ideas: =/
Thankss
You should be able to use a similar approach as I posted in another S/O question. You are on a good track to start. You have your inner query get the counts and have it ordered in the final direction you need. By using inline mysql variables, you can have a holding column of the previous record's value, then use that as computation base for the next result, then set the variable to the new balance to be used for each subsequent cycle.
The JOIN to the SqlVars alias does not have any "ON" condition as the SqlVars would only return a single row anyhow and would not result in any Cartesian product.
select
u.period,
if( #prevCount = -1, 0, u.count_new - #prevCount ) as new_users,
#prevCount := new_users as HoldColumnForNextCycle
from
( select
DATE_FORMAT(u.registration_date,'%Y-%m') as period,
count(distinct u.id) as count_new
from
users u
group by
DATE_FORMAT(u.registration_date,'%Y-%m') ) u
JOIN ( select #prevCount := -1 ) as SqlVars
order by
u.period desc;
You may have to play with it a little as there is no "starting" point in counts, so the first entry in either sorted direction may look strange. I am starting the "#prevCount" variable as -1. So the first record processed gets a new user count of 0 into the "new_users" column. THEN, whatever was the distinct new user count was for the record, I then assign back to the #prevCount as the basis for all subsequent records being processed. yes, it is an extra column in the result set that can be ignored, but is needed. Again, it is just a per-line place-holder and you can see in the result query how it gets its value as each line progresses...
I would create a temp table with two columns and then fill it using a cursor that
does something like this (don't remember the exact syntax - so this is just a pseudo-code):
#val = CURSOR.col2 - (select col2 from OriginalTable t2 where (t2.Period = (CURSOR.Period-1) )))
INSERT tmpTable (Period, NewUsers) Values ( CURSOR.Period, #val)

MySQL multi update keeping the order of IN clause

I want to update the precalculated order of items in a MySQL table in this way
SET #order_item := 1;
UPDATE item
SET item_order := (#order_item := #order_item + 1)
WHERE
id IN (8,2,1,10);
My expected result is:
id, item_order
8, 1
2, 2
1, 3
10, 4
but as MySQL uses PRIMARY KEY index in id to perform the update, I get:
id, item_order
1, 1
2, 3
8, 3
10, 4
I am wondering if you guys know any workaround to face this problem and keep MySQL using the index in a single update. I happen just do it by performing a lot of UPDATES in a PHP bucle. Ideas?
Thanks!
Try ordering it like this.
SET #order_item := 1;
UPDATE item
SET item_order := (#order_item := #order_item + 1)
WHERE
id IN (8,2,1,10)
order by FIELD(id,8,2,1,10);
You can append an ORDER BY clause to your UPDATE query to tell MySQL the order you want it to process the rows. Of course, you need to be able to SELECT the rows in the desired order using the same ORDER BY clause.
But I guess the order is just what you want to achieve :-(

How to distribute records based on column

I have a table storing competition entries.
Contestants must enter text and can optionally upload a photo
When I display entries on a page I paginate through 9 at a time.
How can I ensure as much as possible that each page contains at least one entry with a photo in it (presuming there is enough photo entries for one per page)? It would probably be sufficient to distribute entries with photos evenly amongst the pages
This was one of the more challenging questions I've seen recently -- thanks for that! I'm not able to get it working using a single SQL statement, but I was able to get it working (at least it appears) like this. Basically it tries to determine how many results will be returned, then how many of those have photos, and uses a percentage of the photos divided by the number of pages (using CEILING to ensure at least one for the first few pages).
Anyhow, here goes:
SET #page = 1;
SET #resultsPerPage = 9;
SELECT #recCount:= COUNT(Id) as RecCount
FROM Entries;
SELECT #photoCount:= COUNT(Photo) as PhotoCount
FROM Entries
WHERE Photo IS NOT NULL;
SET #pageCount = CEILING(#recCount/#resultsPerPage);
SET #photosPerPage = CEILING(#photoCount/#pageCount);
SET #nonPhotosPerPage = #resultsPerPage - CEILING(#photosPerPage);
SELECT *
FROM (
SELECT *,
#rownum := #rownum + 1 row_number
FROM Entries JOIN (SELECT #rownum := 0) r
WHERE Photo IS NOT NULL
) a
WHERE a.row_number > (#photosPerPage*(#page-1))
and a.row_number <= (#photosPerPage*(#page))
UNION
SELECT *
FROM (
SELECT *,
#rownum2 := #rownum2 + 1 row_number
FROM Entries JOIN (SELECT #rownum2 := 0) r
WHERE Photo IS NULL
) b
WHERE b.row_number > (#nonPhotosPerPage*(#page-1))
and b.row_number <= (#nonPhotosPerPage*(#page))
And the SQL Fiddle.
Best of luck!
I would suggest that you randomly order the rows:
order by rand()
This doesn't guarantee a photo on every page, but it helps.
The alternative is to do something like this:
select *, #seqnum:=#seqnum+1
from t
where nophoto
select *, #seqnum:=#seqnum+8
from t
where photo
Then sort by seqnum. What makes this cumbersome is handling the cases where there is fewer than one photo per page and more than one photo. The random method is probably sufficient.
For each page, do this (eg for page 3, page size 10):
select ...
from ...
where has_photo
order by created
limit 3, 1
union
select ...
from ...
where not has_photo
order by created
limit 27, 9
This query breaks up the two types of rows into two separate queries recombined by union.

MySQL choose a random row from two joined tables

I know there are simmilar questions out there, but here`s my implementation on a fast random select row:
SELECT i.id, i.thumb_img, i.af, i.width, i.height
FROM images_detail id
JOIN images AS i ON id.imageid = i.id
WHERE id.imageid >=1
AND id.newsroom =1
AND i.width > i.height
AND id.imageid >= FLOOR( 1 + RAND( ) *23111593 )
LIMIT 1
The problem with this query is that indifferent of the RANDOM expression in id.imageid >= FLOOR( 1 + RAND( ) *23111593 ) it always returns the same ID, why?
Any help please?
Later edit:
The query takes 0.0005 seconds, using EXPLAIN, it reports back USING WHERE and 12993 ROWS returned
The Id's are auto-incremented, it's not 23111593 because RAND() returns 0.xxxxx so RAND()*23111593, returns about 12993 rows. The problem is, the same ID is at the top and I don`t want to call an ORDER BY clause.
http://www.greggdev.com/web/articles.php?id=6
or use
ORDER BY RAND() LIMIT 0,1;
Do you have any "imageid" in your database that is greater than the span you define (1<=X<=23111593)?
You might have only one entry in the DB.
(also, keep in mind that you might only have one that actually fits the query of id.newsroom = 1, i.width>i.height etc.)
Eventually I've loaded ALL the results in an array, stored it in a cache and made in PHP $key=rand(0,sizeof(array)) and then used it as follows array[$key]['property']