Calculate ranking in mysql using update query - php

We have calculated ranking using following query.
set #rank = 0;
Update rank_table
set position= (select #rank := #rank + 1)
order by points DESC, points_new DESC, points_old DESC;
And it calculates ranking in sequence.
eg.
I want that id's having same criteria should assign same ranking.
so let say,
here id 1 and 2 have same criteria then should have position=1 and then id 3 should have position=3.
Not like current flow.
Currently -> Id 1:position 1 , Id 2:position 2 , Id 3:position 3
but as Id 1 and 2 have same data it should be..
Id 1:position 1 , Id 2:position 1 , Id 3:position 3
Thanks for your help.

What you want is technically rank() rather than row_number(). This is something of a pain, but possible:
set #rn := 0;
set #rank := 0;
set #p := -1;
Update rank_table
set position = if(#rn := #rn + 1,
if(#p = points, #rank,
if(#p := points, #rank := #rn, #rank := #rn)
),
NULL -- never should happen
)
order by points DESC, points_new DESC, points_old DESC;
This is tricky because you need to calculate both the rank and the row number -- the rank stays the same and then it must "jump" to the row number.

Related

A sort query in SQL by special criteria

I have a table products, and a table product-languages.
products:
prd_id|prd_name
product-languages:
prd_id|language_id|prd_name
1 |1 |Product_German_name
1 |2 |Product_English_name
1 |4 |Product_French_name
I want to join product-languages on prd_id and then sort it by my priority list of language_id (for example: 2,1,4) - first I want the result of lang_id=2, if this is not available I want to have lang_id=1 as the first result.
Is this possible in SQL? I think my personal order list is the problem, because I would have to check if that lang_id is even available...
Subquery maybe?
Thanks
You can do this in standard SQL via case with something like:
select
*
from
products p,
product_languages l
where
p.prd_id = l.prd_id
order by
(case language_id
when 2 then 1
when 1 then 2
when 4 then 3
end) asc
This is a bit of a pain in MySQL, but you can do it. One method uses variables:
select t.*
from (select t.*,
(#rn := if(#prd_id = prd_id, #rn + 1,
if(#prd_id := prd_id, 1, 1)
)
) as rn
from producct_languages t join
(select #prd_id := -1, #rn := 0) params
order by prd_id, field(language_id, 2, 1, 4)
) t
where rn = 1;

Getting sorted mysql records with unique value

I'm trying to get some values from a database but limit it to 1 per account, and I'm having trouble getting it working how I want it.
Here is the query as it stands, which gets the emails in the correct order, and ignores the account:
SELECT ID FROM MailSent
WHERE DateSent IS NULL AND Valid = 1 ORDER BY Priority DESC LIMIT 14
I would like the highest priority record for each account (EmailID). I could just loop through the results and discard any duplicates, but then the actual limit would be a lot lower than the intended one.
Here's a few things I've tried:
SELECT ID, DISTINCT(EmailID) FROM MailSent
WHERE DateSent IS NULL AND Valid = 1 ORDER BY Priority DESC LIMIT 14
// error
SELECT DISTINCT(EmailID), ID FROM MailSent
WHERE DateSent IS NULL AND Valid = 1 ORDER BY Priority DESC LIMIT 14
// still has duplicates
SELECT ID FROM MailSent
WHERE DateSent IS NULL AND Valid = 1 ORDER BY Priority DESC GROUP BY EmailID LIMIT 14
// error
SELECT ID FROM MailSent
WHERE DateSent IS NULL AND Valid = 1 GROUP BY EmailID ORDER BY Priority DESC LIMIT 14
// wrong priority
As a bonus, but not required as it might be quite hard to do, it'd be nice having it limited to a user defined amount instead of just 1.
Just use variables
SELECT ID, EmaailID
FROM (
SELECT ID, EmailID,
#rn := if(#email = EmailID,
#rn + 1,
if(#email := EmailID, 1, 1)
) as rn
FROM MailSent
CROSS JOIN (SELECT #email := 0, #rn := 0) as param
WHERE DateSent IS NULL AND Valid = 1
ORDER BY Priority Desc
) T
WHERE T.rn = 1
Now if you want limit result for user, you need a settings table or a query from somewhere. Just replace previous WHERE for:
JOIN (SELECT userID, numberofRows
FROM SettingTable) P
ON T.ID = P.userID
AND T.rn <= P.numberofRows

how can i find second maximum of my query

Here is my SQL query to find a row in currency_price table grouped by maximum date of inserting to table. My question is how to find the second maximum. I mean how can I change this query to find the second maximum row in each group:
select currency_id,buy,sell
from (select * from currency_price order by `currency_id`, cu_date desc,buy,sell) x
group by `currency_id`
with this query i found a row for each id so for example i have sell and buy for each id .exm:
id sell buy
1000 500 480
1001 20 19
...
but here i want the second maximum date for each id.
I know some query to find second maximum but all does not take me to my answer.
If it is MySql then Use LIMIT 1,1; # Retrieve rows [start with rec]1-[fetch rec count]1
http://dev.mysql.com/doc/refman/5.7/en/select.html
Use ROW_NUMBER()
Sample
SELECT * FROM
(
SELECT *,ROW_NUMBER() OVER (ORDER BY AGE DESC) RNUM FROM TEST_TABLE
) QUERY1 WHERE RNUM=2
You could manually add a group order number to your initial ordered query & then select the second from each row.
The inner query, orders as required & numbers the rows starting from 1, resetting each time the currency_id changes.
set #num := 0, #ci := -1;
select currency_id,buy,sell
from
(select *,
#num := if(#ci = currency_id, #num + 1, 1) as gp_number,
#ci := currency_id as dummy
from currency_price
order by `currency_id`, cu_date desc,buy,sell) x
where gp_number=2
This could be put into a stored procedure from workbench as follows :
DELIMITER $$
CREATE PROCEDURE SecondMaximum()
BEGIN
set #num := 0, #ci := -1;
select currency_id,buy,sell
from
(select *,
#num := if(#ci = currency_id, #num + 1, 1) as gp_number,
#ci := currency_id as dummy
from currency_price
order by `currency_id`, cu_date desc,buy,sell) x
where gp_number=2;
END$$
DELIMITER ;
And from PHP you execute "CALL SecondMaximum();"
If you wanted to be able to change tables and/or fields, then you could pass these as string variables to the procedure & create & execute a prepared statement within the stored procedure. Just do a google search for tutorials on those.

Select 2 random rows from a table from each category MySQL [duplicate]

I have a table with records and it has a row called category. I have inserted too many articles and I want to select only two articles from each category.
I tried to do something like this:
I created a view:
CREATE VIEW limitrows AS
SELECT * FROM tbl_artikujt ORDER BY articleid DESC LIMIT 2
Then I created this query:
SELECT *
FROM tbl_artikujt
WHERE
artikullid IN
(
SELECT artikullid
FROM limitrows
ORDER BY category DESC
)
ORDER BY category DESC;
But this is not working and is giving me only two records?
LIMIT only stops the number of results the statement returns. What you're looking for is generally called analytic/windowing/ranking functions - which MySQL doesn't support but you can emulate using variables:
SELECT x.*
FROM (SELECT t.*,
CASE
WHEN #category != t.category THEN #rownum := 1
ELSE #rownum := #rownum + 1
END AS rank,
#category := t.category AS var_category
FROM TBL_ARTIKUJT t
JOIN (SELECT #rownum := NULL, #category := '') r
ORDER BY t.category) x
WHERE x.rank <= 3
If you don't change SELECT x.*, the result set will include the rank and var_category values - you'll have to specify the columns you really want if this isn't the case.
SELECT * FROM (
SELECT VD.`cat_id` ,
#cat_count := IF( (#cat_id = VD.`cat_id`), #cat_count + 1, 1 ) AS 'DUMMY1',
#cat_id := VD.`cat_id` AS 'DUMMY2',
#cat_count AS 'CAT_COUNT'
FROM videos VD
INNER JOIN categories CT ON CT.`cat_id` = VD.`cat_id`
,(SELECT #cat_count :=1, #cat_id :=-1) AS CID
ORDER BY VD.`cat_id` ASC ) AS `CAT_DETAILS`
WHERE `CAT_COUNT` < 4
------- STEP FOLLOW ----------
1 . select * from ( 'FILTER_DATA_HERE' ) WHERE 'COLUMN_COUNT_CONDITION_HERE'
2. 'FILTER_DATA_HERE'
1. pass 2 variable #cat_count=1 and #cat_id = -1
2. If (#cat_id "match" column_cat_id value)
Then #cat_count = #cat_count + 1
ELSE #cat_count = 1
3. SET #cat_id = column_cat_id
3. 'COLUMN_COUNT_CONDITION_HERE'
1. count_column < count_number
4. ' EXTRA THING '
1. If you want to execute more than one statement inside " if stmt "
2. IF(condition, stmt1 , stmt2 )
1. stmt1 :- CONCAT(exp1, exp2, exp3)
2. stmt2 :- CONCAT(exp1, exp2, exp3)
3. Final "If" Stmt LIKE
1. IF ( condition , CONCAT(exp1, exp2, exp3) , CONCAT(exp1, exp2, exp3) )
share
Use group by instead of order by.

select query which will have return new position column in it

H guys
I just need a select query which will have return new position column in it i.e
i want the result to be
id score position
23 345 1
09 309 2
12 123 3
I tried this but didn't work
(SELECT #rownum := #rownum + 1 AS position,
id,
score
FROM tabs
ORDER BY score DESC");
position row was empty, please help using php
SELECT #rownum := #rownum + 1 AS position,
id,
score
FROM tabs, (SELECT #rownum:=0) AS initrownum
ORDER BY score DESC
your query should be like :SELECT id, score FROM tabs ORDER BY score DESCand your php:for($i = 0; $i < sizeof($result); $i++){echo $i;echo $result['id'][$i];echo $result['score'][$i]//br the line here}

Categories