there is a table having two columns say id and name , i want both columns to be sorted.
table :
id name
3 y
2 z
1 x
output should be
id name
1 x
2 y
3 z
can anybody do it in single sql query ???
You need need to do weird stuff. because what you want to do is weird.
select b1.id, b2.name from
(
select #row := #row +1 as row, id
from broken, (select #row := 0) rr
order by id asc
) b1
inner join
(
select #row2 := #row2 + 1 as row, name
from broken, (select #row2 := 0) rr
order by name asc
) b2
on b1.row = b2.row
demo fiddle: http://sqlfiddle.com/#!9/4d47c/7
Select *
, row_number() over (order by ID) as IDRow
, row_number() over (order by name) as NameRow
into #temp
from table
select a.ID, b.Name from #temp a
full outer join #temp b
on a.IDRow = b.NameRow
order by IDRow, NameRow
If you wanted, you could do this with subqueries instead of the temp table, but it'll probably be faster this way.
Related
The goal
I am trying to write a query to find duplicate rows. A row is duplicate when either Column A or Column B is the same.
Writing it so that both need to be the same is easy; just a simple GROUP BY A, B.
However, filtering by just one of the two is proving to be a bit more difficult. How would one go about doing this?
I've tried the following:
select distinct a as col_a,
b as col_b,
(
select count(*)
from table_name
where a = col_a
or b = col_b
) as duplicate_count
from table_name
having duplicate_count > 1;
but it does not feel like the right way to go about this and with 84.000 rows it is also very slow.
Example
With the following table:
+----+------------------------+---+---------+
| id | name | a | b |
+----+------------------------+---+---------+
| 1 | Lorem ipsum | 1 | Donec |
+----+------------------------+---+---------+
| 2 | dolor sit | 2 | rhoncus |
+----+------------------------+---+---------+
| 3 | amet | 3 | rhoncus |
+----+------------------------+---+---------+
| 4 | consectetur adipiscing | 1 | primis |
+----+------------------------+---+---------+
| 5 | vulputate cursus | 4 | Aliquam |
+----+------------------------+---+---------+
Either result 1 or 4 (same A) and either result 2 or 3 (same B) should be returned, both with a duplicate_count of 2.
Which one of the two "duplicates" is returned does not matter.
Versions
On my local machine I use MySQL 5.7.24.
I just checked the live server, it uses 10.1.43-MariaDB.
You already know that this query:
select a, b
from tablename
group by a, b
having count(*) > 1
returns duplicates with both a and b equal.
You can get the rest of the duplicates for your requirement with EXISTS:
select t.a, t.b
from tablename t
where exists (
select 1 from tablename
where (a = t.a and b <> t.b) or (a <> t.a and b = t.b)
)
Or if you want them all use UNION ALL:
select a, b
from tablename
group by a, b
having count(*) > 1
union all
select t.a, t.b
from tablename t
where exists (
select 1 from tablename
where (a = t.a and b <> t.b) or (a <> t.a and b = t.b)
)
Update:
If you have an ID column then use EXISTS like this:
select t.*
from tablename t
where exists (
select 1 from tablename
where id <> t.id and (a = t.a or b = t.b)
)
Or if you want just 1 of the duplicates use id > t.id instead of id <> t.id.
See the demo.
Or with a self join:
select t.*
from tablename t inner join tablename tt
on (tt.a = t.a or tt.b = t.b) and tt.id <> t.id
Following solution works :
Another demo with a line that has duplication in a and b
CREATE TEMPORARY TABLE ab_duplicates (
a INTEGER
) AS
SELECT a, count(*) as cnt
FROM tablename
group by a, b
Having cnt > 1;
ALTER TABLE ab_duplicates ADD INDEX (a);
-- Select duplicates for a, but not for a and b
SELECT id, name, a, b
FROM (SELECT x.*, t.id, t.name, t.a, t.b,
#rn := IF(t.a = #a, #rn + 1, 1) rn,
#a := t.a,
ab.a as ab_exists
FROM (select #a := null, #rn := 0) x,
tablename t
LEFT JOIN ab_duplicates ab on ab.a = t.a
ORDER BY a
) a_duplicates
where rn = 2 and ab_exists is null
UNION
-- union duplicates for b, including duplicates for a and b
SELECT id, name, a, b
FROM (SELECT x.*, t.id, t.name, t.a, t.b,
#rn := IF(t.b = #b, #rn + 1, 1) rn,
#b := t.b
FROM (select #b := null, #rn := 0) x,
tablename t
ORDER BY b
) b_and_ab_duplicates
where rn = 2;
Previous solutions that only worked in some edge cases
Using group by and count() :
First finding ids with duplicates for a :
SELECT min(id) id, count(*) cnt from tablename t group by a having cnt > 1
-- this will work better if you have an index starting with a
Same with b :
SELECT min(id) id, count(*) cnt from tablename t group by b having cnt > 1
-- this will work better if you have an index starting with b
First solution :
Union gives you ids where there are duplicates for a or b requires 2 indices)
SELECT min(id) id, count(*) cnt from tablename t group by a having cnt > 1
UNION
SELECT min(id) id, count(*) cnt from tablename t group by b having cnt > 1
Use the ids to filter the table, if you need more data from the table :
SELECT tablename.*
FROM (
SELECT min(id) id, count(*) cnt from tablename t group by a having cnt > 1
UNION
SELECT min(id) id, count(*) cnt from tablename t group by b having cnt > 1
) as ids
JOIN tablename on tablename.id = ids.id
Now this might not use an index, but you can use a temporary table to have one :
First solution, using a temporary table (might be faster) :
-- using a temporary table to set an index
CREATE TEMPORARY TABLE ids (
-- adds an index on id, for the JOIN in the result query
`id` INTEGER PRIMARY KEY
) as
SELECT id
FROM (
-- duplicates on a, requires an index (a) on tablename
SELECT min(id) id, count(*) cnt from tablename t group by a having cnt > 1
-- removes duplicates between both part of the UNION : this might be slow
-- if there cannot be duplicates on a and b at the same time, consider using UNION ALL
UNION
-- duplicates on b, requires an index (b) on tablename
SELECT min(id) id, count(*) cnt from tablename t group by b having cnt > 1
) tempids;
SELECT tablename.*
FROM ids -- using the temporary table, MUST be in the same database connection, will filter duplicates
JOIN tablename on tablename.id = ids.id;
I do not know if setting the index on the temporary table is better then setting one after populating the data :
-- you might want to postpone the index after the ids are set
-- using a temporary table to set an index
CREATE TEMPORARY TABLE ids2 (
`id` INTEGER
) as
SELECT id
FROM (
-- duplicates on a, requires an index (a) on tablename
SELECT min(id) id, count(*) cnt from tablename t group by a having cnt > 1
-- removes duplicates between both part of the UNION : this might be slow
-- if there cannot be duplicates on a and b at the same time, consider using UNION ALL
UNION
-- duplicates on b, requires an index (b) on tablename
SELECT min(id) id, count(*) cnt from tablename t group by b having cnt > 1
) tempids;
ALTER TABLE ids2 ADD INDEX (id);
SELECT tablename.*
FROM ids2 -- using the temporary table, MUST be in the same database connection, will filter duplicates
JOIN tablename on tablename.id = ids2.id;
With mariadb 10.2, or mysql 8 you could use window function (I guess).
Another solution : using vars :
SELECT id, name, a, b, rn
FROM (SELECT *,
#rn := IF(a = #a, #rn + 1, 1) rn,
#a := a
FROM (select #a := null, #rn := 0) x,
tablename
ORDER BY a
) a_duplicates
where rn = 2
UNION
SELECT id, name, a, b, rn
FROM (SELECT *,
#rn := IF(b = #b, #rn + 1, 1) rn,
#b := b
FROM (select #b := null, #rn := 0) x,
tablename
ORDER BY b
) b_duplicates
where rn = 2
Demo : with some extra steps to understand
Edit : this only works if you don t have lines where a and b are duplicates. Which is the case in the example.
I'm trying to select first row then skip X next rows then select rest in one query. For example if I have (a,b,c,d,e) in table I need to select "a" (first row) then skip X=2 rows ("b", "c") and then select rest which is "d" and "e", all in one query. So the result would be a,d,e
Try
select *
from
(
select *, #rank := #rank + 1 as rank
from your_table
cross join (select #rank := 0) r
order by colA
) tmp
where rank = 1
or rank > 3
or
select * from your_table
order by colA
limit 1
union all
select * from your_table
order by colA
limit 4, 9999999
You can use a variable to generate a row number:
select
YourField,
YourOtherField
from
(
select id,
YourField,
YourOtherField,
#row := #row + 1 as rownum
from YourTable
cross join (select #row:=0) c
order by YourField -- The field you want to sort by when you say 'first' and 'fourth'
) d
where
rownum = 1 or rownum >= 4
I have the table with data:
And for this table I need to create pegination by productId column. I know about LIMIT N,M, but it works with rows and not with groups. For examle for my table with pegination = 2 I expect to retrieve all 9 records with productId = 1 and 2 (the number of groups is 2).
So how to create pegination by numbers of groups ?
I will be very thankfull for answers with example.
One way to do pagination by groups is to assign a product sequence to the query. Using variables, this requires a subquery:
select t.*
from (select t.*,
(#rn := if(#p = productid, #rn + 1,
if(#rn := productid, 1, 1)
)
) as rn
from table t cross join
(select #rn := 0, #p := -1) vars
order by t.productid
) t
where rn between X and Y;
With an index on t(productid), you can also do this with a subquery. The condition can then go in a having clause:
select t.*,
(select count(distinct productid)
from t t2
where t2.productid <= t.productid)
) as pno
from t
having pno between X and Y;
Try this:
select * from
(select * from <your table> where <your condition> group by <with your group>)
LIMIT number;
I have table with id (store user id) and score in different match. I want what is the position of a user.
So for i try this sql fiddle;
in this I am getting all the row but I need only user having id 3 and it position in the table.
like this:
Score Postion
26 3
Even i try to do like this but no success
MySql: Find row number of specific record
With MySQL, how can I generate a column containing the record index in a table?
I got the answer: http://sqlfiddle.com/#!2/b787a/2
select * from (
select T.*,(#rownum := #rownum + 1) as rownum from (
select sum(score) as S,id from mytable group by id order by S desc ) as T
JOIN (SELECT #rownum := 0) r
) as w where id = 3
Updated sqlfiddle and above query. Now it is working perfectly.
I think this should do the trick:
SELECT totalScore, rownum FROM (
SELECT id,sum(score) AS totalScore,(#rownum := #rownum + 1) AS rownum
FROM mytable
JOIN (SELECT #rownum := 0) r
group by id) result
WHERE result.ID = 3;
just add a where clause
select x.id,x.sum,x.rownum
from(
select id,sum(score) as sum,(#rownum := #rownum + 1) as rownum
from mytable
JOIN (SELECT #rownum := 0) r
group by id
) x
where id =3
Considering following table that doesn't have any primary key, can I select every other row?
col1 col2
2 a
1 b
3 c
12 g
first select must find: 2, 3
second select must find: 1, 12
is that possible?
In unique MySQL fashion:
select *
from (
select *
, #rn := #rn + 1 as rn
from Table1
join (select #rn := 0) i
) s
where rn mod 2 = 0 -- Use = 1 for the other set
Example at SQL Fiddle.
Try this. I've adapted it from the answer linked below.
I tested it on SQLFiddle and it appears to work.
http://sqlfiddle.com/#!2/0bccf/28
http://sqlfiddle.com/#!2/0bccf/29
Odd Rows:
SELECT x.*
FROM (
SELECT #rownum:=#rownum+1 rownum, t.*
FROM (SELECT #rownum:=0) r, table t
) x
WHERE MOD(x.rownum, 2) = 1
Even Rows:
SELECT x.*
FROM (
SELECT #rownum:=#rownum+1 rownum, t.*
FROM (SELECT #rownum:=0) r, table t
) x
WHERE MOD(x.rownum, 2) = 0
Adapted from:
MySQL row number
yes possible using temp variable
Example :
set #a := 0;
select * from car_m_city WHERE mod((#a:=#a+1), 2) = 1
Explanation :
here in sql we declare #a( set #a := 0;) temp variable.(#a:=#a+1) now #a increment by 1.jsut like simple way to check odd or even
mod((#a:=#a+1), 2) = 1 for odd data
mod((#a:=#a+1), 2) = 0 for even data
This works for me.
SET #row_number = 0;
select* from (
SELECT
(#row_number:=#row_number + 1) AS num, col1,col2
FROM
TABLE1
) as t WHERE num%2=0
You can use mod 1 for odd or mod 0 for even rows
This should work for MySQL:
SELECT col1, col2
FROM (
SELECT col1, col2, #rowNumber:=#rowNumber+ 1 rn
FROM YourTable
JOIN (SELECT #rowNumber:= 0) r
) t
WHERE rn % 2 = 1
This uses % which is the MOD operator.
And here is the sample fiddle: http://sqlfiddle.com/#!2/cd31b/2