Select Top 1 row for distinct id sqlite - mysql

I got following table content :
> id text time
> 1 Hi 2
> 2 Hello 1
> 1 Mr. SP 3
> 3 KK 1
> 2 TT 2
> 1 Sample 1
> 1 App 4
and i need to select distinct values for id with text, hence output should be:
id text time
1 App 4
2 TT 2
3 KK 1
Can anyone help me out with this query.
I'm using Sqlite
Thanks

select b.*
from
(
select id, max(time) as time
from yourtable
group by id) a inner join yourtable b on a.time = b.time and a.id = b.id
working demo: http://sqlfiddle.com/#!5/fbb87/5

You seem to want the value with the maximum time. The following is often an efficient way to get this:
select t.*
from table t
where not exists (select 1 from table t2 where t2.id = t.id and t2.time > t.time);
What this is saying is: "Get me all rows from the table where the id does not have a row with a larger id". With an index on table(id, time), this is probably the most efficient way to express this query.

select * from (
select id,[text],
ROW_NUMBER() OVER (PARTITION BY id ORDER BY [time] desc) as rn
from [table]) as cte
where rn = 1

Related

SQL add same contents

How can I delete all columns that are duplicate and don't have the biggest "amount". I have the following table:
ID TIME AMOUNT
-----------------------------------
1 x 5
2 y 1
2 y 3
3 z 1
3 z 2
3 z 3
But I want it to be like this, so that only the column which has the biggest number "survives":
ID TIME AMOUNT
------------------------------------
1 x 5
2 y 3
3 z 3
How can I do this?
You can get the max amount per id and time and then get the rows matching:
select t.Id, t.Time, t.amount
from myTable t
inner join
(select Id, time, max(amount) as amt
from myTable
group by Id, Time) tmp on t.id = tmp.id and
t.time = tmp.time and
t.amount = tmp.amt
DbFiddle demo
EDIT: You may want to add DISTINCT depending on your needs.
One other approach using a CTE
with del as (
select *,
First_Value(amount) over(partition by id order by amount desc) maxamount
from t
)
delete from t
using t join del on t.id = del.id and t.amount < maxamount;
WITH cte AS
(
SELECT
ID,
ROW_NUMBER() OVER (PARTITION BY TIME ORDER BY AMOUNT DESC) AS ROWNUM
FROM
MyTable
)
DELETE MyTable
FROM MyTable
JOIN cte USING (ID)
WHERE ROWNUM > 1;
WITH syntax requires MySQL 8.0.
I think some of the answers here are overly complicated.
delete t
from yourtable t
join yourtable t2 on t.id = t2.id
and t.time = t2.time
and t2.amount > t.amount

Select all orders except the max order for each distinct customer

Sorry for the poor formatting but as part of a larger problem, I have created a query that produces this table:
id id2
4 7
4 6
1 3
1 2
1 1
How would I extract the rows that don't have the highest id2 for each id1.
What I want:
id id2
4 6
1 2
1 1
I can only seem to figure out how to get rid of the max id2 overall but not for each distinct id1. Any help on actually differentiating the max id2 for each id1 would be appreciated.
You can try below way -
select a.id, a.id2
from tablename a
where a.id2 <> (select max(a1.id2) from tablename a1 where a.id=a1.id)
If you are using MySQL 8+, then RANK() provides one option:
WITH cte AS (
SELECT id, id2, RANK() OVER (PARTITION BY id ORDER BY id2 DESC) rnk
FROM yourTable
)
SELECT id, id2
FROM cte
WHERE rnk > 1
ORDER BY id DESC, id2 DESC;
Demo
instead of a correlated subquery in the where, you can LEFT JOIN and apply not in...
select id, id2
from yourTable YT
LEFT JOIN
( select id, max( id2 ) highestID2
from YourTable
group by id ) TopPerID
on YT.ID = TopPerID.ID
AND YT.ID2 != TopPerID.highestID2
where TopPerID.id IS NULL
Since you can have id values with only one id2 value, you need to check for that situation as well, which you can do by comparing the MAX(id2) value with the MIN(id2) value in a JOIN:
SELECT t1.*
FROM Table1 t1
JOIN (SELECT id, MAX(id2) AS max_id2, MIN(id2) AS min_id2
FROM Table1
GROUP BY id) t2 ON t2.id = t1.id
AND (t1.id2 < t2.max_id2 OR t2.min_id2 = t2.max_id2)
If we add a row 2, 5 to your sample data this correctly gives the result as
id id2
4 6
1 2
1 1
2 5
Demo on SQLFiddle

Condensing MySQL ordered group values

This question is an extension of mysql compress order_by values.
My table has groups of ordered numbers, with undesired gaps. How can I renumber each of these groups, while keeping the original order?
Group Order Desired Order
A 1 1
A 3 2
A 6 3
A 7 4
B 2 1
B 3 2
B 8 3
C 1 1
C 7 2
C 8 3
You can also get the desired order by using a correlated sub query without using and variables
select t1.*,
(
select count(*)
from demo t2
where t1.`group` = t2.`group`
and t1.`order` > t2.`order`
) + 1 desiredorder
from demo t1
DEMO
Or to update same table with your desired order you can use below query
update demo a
join (select t1.*,(
select count(*)
from demo t2
where t1.`group` = t2.`group`
and t1.`order` > t2.`order`
) + 1 desiredorder
from demo t1
) b on a.`group` = b.`group`
and a.`order` = b.`order`
set a.`order` = b.desiredorder
DEMO
Note make sure to add an index on group and order column for better performance.
You can create a variable to store the previous value of group and another one for the desiredorder. Essentially this is a mimic of a Window Function ROW_NUMBER which MySql doesn't support.
I renamed the columns as group=col1, order=col2
select col1,
col2,
neworder
from (
select t.col1,
t.col2,
case when #prev=t.col1 then #id:=#id+1 else #id:=1 end as neworder,
#prev:=t.col1
from (select #prev:=null, #id:=0) a,
toorder t
order by t.col1
) a
See it working here: http://sqlfiddle.com/#!9/9d8528/2
The external query is only needed if you want to pull out only those three columns.

repeat result multiple times in mysql

I have a table having id and no field, what I really want is the result raw will be repeated no filed times, if the no field is 2 then that raw must be repeated twice in result.
this is my sample table structure:
id no
1 3
2 2
3 1
now I need to get a result like:
1 3
1 3
1 3
2 2
2 2
3 1
I tried to write mysql query to get the result like above, but failed.
You need a table of numbers to accomplish this. For just three values, this is easy:
select t.id, t.no
from t join
(select 1 as n union all select 2 union all select 3
) n
on t.no <= n.no;
This query must do what you want to achieve:
select t.id, t.no from test t cross join test y where t.id>=y.id
not completely solve your problem, but this one can help
set #i=0;
select
test_table.*
from
test_table
join
(select
#i:=#i+1 as i
from
any_table_with_number_of_rows_greater_than_max_no_of_test_table
where
#i < (select max(no) from test_table)) tmp on no >= i
order by
id desc
EDIT :
This is on SQL Server. I checked online and see that CTEs work on MySQL too. Just couldn't get them to work on SQLFiddle
Try this, remove unwanted columns
create table #temp (id int, no int)
insert into #temp values (1, 2),(2, 3),(3, 5)
select * from #temp
;with cte as
(
select id, no, no-1 nom from #temp
union all
select c.id, c.no, c.nom-1 from cte c inner join #temp t on t.id = c.id and c.nom < t.no and c.nom > 0
)
select * from cte order by 1
drop table #temp

Mysql query random order (pause and continue) question

Okay i am trying to create a mysql query that does this:
show 3 random records from table then after the 3th record show TEXT
and then show the same 3 items but other field (equaling to the items ofcourse) from same table.
eg table info:
--ids | titles------
10 | one
20 | two
30 | three
and the query results from the given example:
30 10 20 TEXT three one two
if anyone understand what i am asking,post your suggestion/asnwer
thanks for your time all :)
Just for kicks..
select t1.id, t2.id, t3.id, 'TEXT', t1.title, t2.title, t3.title
FROM
(
select #r := #r + 1 rownum, id
from (select #r:=0) initvar, (
select id
from tbl
order by rand()
limit 3
) X
) Y
join tbl t1 on Y.rownum=1 and t1.id = Y.id
join tbl t2 on Y.rownum=2 and t2.id = Y.id
join tbl t3 on Y.rownum=3 and t3.id = Y.id
You should really just do the query below, and do whatever display processing using the 3 rows returned, in whatever programming environment you use (Java/PHP/.Net etc).
select id, title
from tbl
order by rand()
limit 3
EDIT
To get the data in 7 different rows, you can use the below. I stress again that this is front-end display code. I will not use such SQL code in a production system.
select display
from
(
select sorter, rownum,
case when sorter=3 then title else id end display
from
(
select #r := #r + 1 rownum, id, title
from (select #r:=0) initvar,
(
select id, title
from tbl
order by rand()
limit 3
) X
) Y, (select 1 sorter union all select 3) dup
union all
select 2, 0, 'TEXT'
) Z
order by sorter, rownum
Example Output
7
2
1
TEXT
test 7 << title for id=7
test 2
test 1