How to get row number in select query mysql - mysql

I try to get all the years in a table with 174 rows. There is two differents years 2016 and 2017. And add to the query's response and Id which correspond at the "row count" of the response.
Here is the query :
SET #n=0;
SELECT YEAR (`Date`) AS Libelle, #n := #n + 1 AS id FROM Datas GROUP by Libelle
The response is :
|Libelle| Id|
| 2016| 1|
| 2017|174|
What's the way to get :
|Libelle| Id|
| 2016| 1|
| 2017| 2|
174 corresponds to the last record in my table. And I understand that's #n is incremented with all other rows.
Have you an idea to do this ?

try this. so the counter works only on the result:
SELECT #n := #n + 1 AS id , tmp.*
FROM (
SELECT DISTINCT YEAR (`Date`) AS Libelle FROM Datas GROUP by Libelle ) AS tmp,
( SELECT #n := 0) as parameter;

Something like this perhaps?
SELECT
t1.Libelle,
#n := #n + 1 AS id
FROM (
SELECT DISTINCT YEAR(`Date`) AS Libelle
FROM Datas
GROUP BY Libelle
) t1,
(
SELECT #n := 0
) t2;
Related: https://stackoverflow.com/a/4474389/4152813

Related

Insert distinct records of one table to another into MySQL

Table 1:mydata_table
Multiple Columns. But I want to fetch 3 columns' distinct records.
Email_Office | Email_Personal1 | Email_Personal2
Table 2:unique_emails
Only 3 Columns. Email_Office | Email_Personal1 | Email_Personal2
I tried this code for all three columns of table 2 to insert distinct records from each column.
insert into unique_emails
(email_personal1)
select distinct email_personal1
from mydata_table
where Email_Personal1!=""
It inserts the records but the problem is if there are 100 rows in email_office column and 300 rows in email_personal1 then it will show first 100 rows with email_office and remaining two columns are empty, then from 101th row, it will show email_personal1's records and remaining two columns are empty. I want to insert all rows together. How can I do that?
Try to creare unique index for columns that needs to be unique, and use the first SQL proposed by #Sergey with ignore:
INSERT IGNORE INTO
unique_emails
(email_office, email_personal1, email_personal2)
SELECT DISTINCT
email_office,
email_personal1,
email_personal2
FROM
mydata_table
WHERE
email_office!=""
OR Email_Personal1!=""
OR Email_Personal2!=""
If you want to insert unique triples of e-mails, you should use
insert into unique_emails
(email_office, email_personal1, email_personal2)
select distinct email_office, email_personal1, email_personal2
from mydata_table
where email_office!="" OR Email_Personal1!="" OR Email_Personal2!=""
But in that case some emails may occur multiple times in table unique_emails.
Supposing Table 1 consist of records:
Email_Office | Email_Personal1 | Email_Personal2
------------------------------------------------
a#a.com b#b.com c#c.com
a#a.com b#b.com c#c.com
a#a.com b#b.com e#e.com
a#a.com c#c.com NULL
a#a.com d#d.com e#e.com
then result Table 2
Email_Office | Email_Personal1 | Email_Personal2
------------------------------------------------
a#a.com b#b.com c#c.com
c#c.com e#e.com
d#d.com
UPD.
Try this: (SQL Fiddle)
insert into unique_emails
(email_office, email_personal1, email_personal2)
select b.email_office, c.email_personal1, d.email_personal2
from (
select #i := #i + 1 AS pos from mydata_table, (select #i := 0) r) a
left join (
select t.*, #j := #j + 1 AS pos
from (select distinct email_office from mydata_table where email_office!="") t,
(select #j := 0) r) b on b.pos = a.pos
left join (
select t.*, #k := #k + 1 AS pos
from (select distinct email_personal1 from mydata_table where email_personal1!="") t,
(select #k := 0) r) c on c.pos = a.pos
left join (
select t.*, #l := #l + 1 AS pos
from (select distinct email_personal2 from mydata_table where email_personal2!="") t,
(select #l := 0) r) d on d.pos = a.pos
where b.email_office is not null or c.email_personal1 is not null or d.email_personal2 is not null

SQL filter rows without join

I'm always "irk" by unnecessary join. But in this case, I wonder if it's possible to not use join.
This is an example of the table I have:
id | team | score
1 | 1 | 300
2 | 1 | 257
3 | 2 | 127
4 | 2 | 533
5 | 3 | 459
This is what I want:
team | score | id
1 | 300 | 1
2 | 533 | 4
3 | 459 | 5
Doing a query looking like this:
(basically: who's the best player of each team)
SELECT team, MAX(score) AS score, id
FROM my_table
GROUP BY team
But I get something like that:
team | score | id
1 | 300 | 1
2 | 533 | 3
3 | 459 | 5
But it's not the third player that got 533 points, so the result have no consistency.
Is it possible to get truthworthy results without joining the table with itself? How to achieve that?
You can do it without joins by using subquery like this:
SELECT id, team, score
FROM table1 a
WHERE score = (SELECT MAX(score) FROM table1 b WHERE a.team = b.team);
However in big tables this can be very slow as you have to run the whole subquery for every row in your table.
However there's nothing wrong with using join to filter results like this:
SELECT id, team, score FROM table1 a
INNER JOIN (
SELECT MAX(score) score, team
FROM table1
GROUP BY team
) b ON a.score = b.score AND a.team = b.team
Although joining itself is quite expensive, this way you only have to run two actual queries regardless how many rows are in your tables. So in big tables this method can still be hundreds, if not thousands of times faster than the first method with subquery.
You can use variables:
SELECT id, team, score
FROM (
SELECT id, team, score,
#seq := IF(#t = team, #seq,
IF(#t := team, #seq + 1, #seq + 1)) AS seq,
#grp := IF(#t2 = team, #grp + 1,
IF(#t2 := team, 1, 1)) AS grp
FROM mytable
CROSS JOIN (SELECT #seq := 0, #t := 0, #grp := 0, #t2 := 0) AS vars
ORDER BY score DESC) AS t
WHERE seq <= 3 AND grp = 1
Variable #seq is incremented each time a new team is met as the records are being processed in descending score order. Variable #grp is used to enumerate records within each team partition. Records with #grp = 1 are the ones having the greatest score value within the team slice.
Demo here
Unfortantly , MySQL doesn't support window functions like ROW_NUMBER() which could have solved this easily.
There are several ways on doing that:
NOT EXISTS() :
SELECT * FROM YourTable t
WHERE NOT EXISTS(SELECT 1 FROM YourTable s
WHERE t.team = s.team AND s.score > t.score)
NOT IN() :
SELECT * FROM YourTable t
WHERE (t.team,t.score) IN(SELECT s.team,MAX(s.score)
FROM YourTable s
GROUP BY s.team)
A correlated query:
SELECT distinct t.id,t.team,
(SELECT s.score FROM YourTable s
WHERE s.team = t.team
ORDER BY s.score DESC
LIMIT 1)
FROM YourTable t
Or a join which I understand you already have.
EDIT : I take my words back, you can do it with a variable like #GiorgosBetsos solution.
You could do something like this:
SELECT team, score, id
FROM (SELECT *
,RANK() OVER
(PARTITION BY team ORDER BY score DESC) AS Rank
FROM my_table) ranked_result
WHERE Rank = 1;
Some info on Rank functionality: Clicketyclickclick

Query to fetch multiple columns with distinct values for one of these

I have a table with the following columns : id, int_value, date, desc . Primary key is (id, int_value, date).
I would like to query the table to get id, int_value and date columns but with distinct id and int_value ordered in desc.
For example, imagine you have the following rows in the table
id | int_value | date | desc
1 150 2016 desccc
2 120 2014 ddd
1 160 2016 aaa
3 180 2015 ccc
2 135 2016 ddd
With my query, I would like to get that :
id | int_value | date | desc
3 180 2015 ccc
1 160 2016 aaa
2 135 2016 ddd
For the moment, I made the following query :
select id, int_value, date from table t where int_value = (select
max(int_value) from table where t.id = id) order by int_value desc;
It works well but if there are same int_value values for a given id, there will be two rows for the same id.
My question is : can you help me to create a query to avoid this problem ?
Update
It seems the following query do the job :
SELECT id, MAX(int_value) AS score, date FROM table GROUP BY id order by score desc
Thanks for your help.
Sylvain
One method is to emulate row_number() using variables:
select id, int_value, date
from (select id, int_value, date,
(#rn := if(#i = id, #rn + 1,
if#i := id, 1, 1)
)
) as rn
from table t cross join
(select #i := 0, #rn := 0) params
order by id, int_value desc
) t
where rn = 1;
select a.*, b.[desc] from
(select id, max(int_value) as int_value, max(date) as date from YourTableName group by id) a
left join YourTableName b on (a.id=b.id and a.int_value=b.int_value and a.date=b.date)
order by date
this produces the result you want:
id int_value date desc
----------- ----------- ----------- ------
3 180 2015 ccc
1 160 2016 aaa
2 135 2016 ddd
(3 row(s) affected)

Count row number from a mysql table subquery

I have a table department_courses with following structure :
id department_id name
-- ------------- -----
1 11 Abcd
2 11 Bghg
3 11 Lopps
4 13 Abvgf
So from this table I need to count the position of the subquery. I mean to say , The position of the name Lopps for department_id is 3 . How to get this in mysql query?
If you only need to do this for one row, then a single query is simpler:
select count(*)
from department_courses dc
where dc.id <= (select dc2.id
from department_courses dc2
where dc2.name = 'Lopps'
);
If you want to assign a row number to all rows, then variables are probably a better method.
Try:
select row_num
from (
select t.*, #r := #r + 1 row_num
from department_courses t,
(select #r := 0) r
) x
where x.name = 'Lopps'
x.department_id = 3

MySQL return 2 rows per result

Until today i thought i know something about MySQL.
OK lets say we have one table like this:
id | some_name |some_number
-----------------------------
1 | test | 33
2 | test | 34
3 | test | 35
3 | test2 | 36
3 | test2 | 37
and i want to write query to return something like this:
test 33
test 34
test2 36
test2 37
test3 12
test3 34
.
.
.
and so on. I want to return only 2 result per same name. It is easy to use limit and return only one result per name but I'm stuck to return multiple results per same name in this case 2 but might be an n results. Work around is to make some script that will do:
select some_name, some_number from tbl_name limit 2;
and to repeat it for every distinct some_name i have in table.
Is there any elegant solution for MySQL? I would be grateful if you share that with me.
You can use a user variable to add a counter of each row of a name, then just select the rows where the counter is less than or equal to 2 (untested):-
SELECT some_name, some_number
FROM
(
SELECT some_name, some_number, #cnt=(#some_name = some_name, #cnt + 1, 1) AS cnt, #some_name:=some_name
FROM
(
SELECT some_name, some_number
FROM tbl_name
ORDER BY some_name, some_number
) sub0
CROSS JOIN
(
SELECT #some_name:='', #cnt:=0
)
sub1
) sub2
WHERE cnt <= 2
you could try this,
select some_name,some_number from yourTable t
where
(select count(*) from yourTable
where
some_number<=t.some_number and some_name=t.some_name)<3
This partially solved my problem:
set #num := 0, #name := '';
select distinct number, name
from (
select number, name,
#num := if(#name = name, #num +1, 1) as row_number,
#name := name as dummy
from karian2
) as x where x.row_number <= 2;
It fails some time to return 2 results because sub query is not returning distinct values. Example here:
http://sqlfiddle.com/#!2/952ca/23