I have the following data in database, the primary key is the field SEQ, I wish to select the data which has the maximum seq:
ID SEQ FILE
1007 1 abc
1007 2 def
The following query is invalid but I wish to do the same thing as following.
SELECT * FROM table1 WHERE id = '1007' AND Max(seq)
SELECT id, seq, file
FROM (
select id, seq, file,
max(seq) over (partition by id) as max_seq
from table1
WHERE id = '1007'
) t
where seq = max_seq;
If I understood right, you wish something like this
select *
from (select t.*,
max(t.seq)
keep (dense_rank first order by t.seq desc)
over (partition by t.id) max#
from table1 t)
where seq = max#
Another approach:
select id,seq,"FILE" from
(select t1.*,row_number() over (partition by id order by seq desc) cont_seq
from your_table t1)
where cont_seq = 1
order by seq;
This will give you all rows grouped by id who has the max seq value. If you want an specific value just add the condition in the where clause like this:
select id,seq,"FILE" from
(select t1.*,row_number() over (partition by id order by seq desc) cont_seq
from your_table t1)
where cont_seq = 1 and id = '1007'
order by seq;
select * from alber.table1;
MYID SEQ FILENAME
1007 2 abc
1007 10 def
1008 45 abc
1008 9 def
SELECT myid, seq, filename from alber.table1 mq
where seq = (select max(seq) from alber.table1 sq where sq.myid = mq.myid);
MYID SEQ FILENAME
1007 10 def
1008 45 abc
Related
I have a table like this:
ID | name
45 Alex
98 Diana
32 Peter
98 Daniel
45 Alex
23 Bob
98 Jake
I need to find all rows where is the same ID but different name.
You could use first/last value() window functions here:
with n as (
select *,
First_Value(name) over(partition by id order by (select null)) n1,
Last_Value(name) over(partition by id order by (select null)) n2
from t
)
select Id, Name
from n
where n1 != n2
You can use exists:
select t.*
from mytable t
where exists (select 1
from mytable t2
where t2.id = t.id and t2.name <> t.name
);
A windowed count is usually the most efficient:
SELECT
t.ID,
t.name
FROM (
SELECT *,
c = COUNT() OVER (PARTITION BY t.name)
FROM YourTable t
) t
WHERE c > 1;
SELECT
ID,
name,
CASE WHEN COUNT(ID) OVER(PARTITION BY ID) = 1 THEN 'OK' ELSE 'NOT OK' END AS CountID
FROM Table
GROUP BY ID,name
ORDER BY ID
Example:
I need to group by id and select the task with min/max seq as start and end
id | task | seq
----+------+-----
1 | aaa | 1
1 | bbb | 2
1 | ccc | 3
SELECT
id,
CASE WHEN seq = MIN(seq) THEN task AS start,
CASE WHEN seq = MAX(seq) THEN task AS end
FROM table
GROUP BY id;
But this results in
ERROR: column "seq" must appear in the GROUP BY clause or be used in an aggregate function
But I do not want group by seq
One method uses arrays:
SELECT id,
(ARRAY_AGG(task ORDER BY seq ASC))[1] as start_task,
(ARRAY_AGG(task ORDER BY seq DESC))[1] as end_task
FROM table
GROUP BY id;
Another method uses window functions with SELECT DISTINCT:
select distinct id,
first_value(task) over (partition by id order by seq) as start_task,
first_value(task) over (partition by id order by seq desc) as end_task
from t;
You can use window functions with a derived table:
select id, task, min_seq as start, max_seq as "end"
from (
select id, task, seq,
max(seq) over (partition by id) as max_seq,
min(seq) over (partition by id) as min_seq
from the_table
) t
where seq in (max_seq, min_seq)
One option here would be to use ROW_NUMBER along with aggregation and pivoting logic:
WITH cte AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY seq) rn_min,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY seq DESC) rn_max
FROM yourTable
)
SELECT
id,
MAX(CASE WHEN rn_min = 1 THEN task END) AS start,
MAX(CASE WHEN rn_max = 1 THEN task END) AS end
FROM cte
GROUP BY
id;
Demo
I want to create a SQL query that SELECT a ID column and adds an extra column to the query which is a group number as shown in the output below.
Each group consists of 3 rows and should have the MIN(ID) as a GroupID for each group. The order by should be ASC on the ID column.
ID GroupNr
------------
100 100
101 100
102 100
103 103
104 103
105 103
106 106
107 106
108 106
I've tried solutions with ROW_NUMBER() and DENSE_RANK(). And also this query:
SELECT
*, MIN(ID) OVER (ORDER BY ID ASC ROWS 2 PRECEDING) AS Groupnr
FROM
Table
ORDER BY
ID ASC
Use row_number() to enumerate the rows, arithmetic to assign the group and then take the minimum of the id:
SELECT t.*, MIN(ID) OVER (PARTITION BY grp) as groupnumber
FROM (SELECT t.*,
( (ROW_NUMBER() OVER (ORDER BY ID) - 1) / 3) as grp
FROM Table
) t
ORDER BY ID ASC;
It is possible to do this without a subquery, but the logic is rather messy:
select t.*,
(case when row_number() over (order by id) % 3 = 0
then lag(id, 2) over (order by id)
when row_number() over (order by id) % 3 = 2
then lag(id, 1) over (order by id)
else id
end) as groupnumber
from table t
order by id;
Assuming you want the lowest value in the group, and they are always groups of 3, rather than the NTILE (as Saravantn suggests, which splits the data into that many even(ish) groups), you could use a couple of window functions:
WITH Grps AS(
SELECT V.ID,
(ROW_NUMBER() OVER (ORDER BY V.ID) -1) / 3 AS Grp
FROM (VALUES(100),
(101),
(102),
(103),
(104),
(105),
(106),
(107),
(108))V(ID))
SELECT G.ID,
MIN(G.ID) OVER (PARTITION BY G.Grp) AS GroupNr
FROM Grps G;
SELECT T2.ID, T1.ID
FROM (
SELECT MIN(ID) AS ID, GroupNr
FROM
(
SELECT ID, ( Row_number()OVER(ORDER BY ID) - 1 ) / 3 + 1 AS GroupNr
FROM Table
) AS T1
GROUP BY GroupNr
) AS T1
INNER JOIN (
SELECT ID, ( Row_number()OVER(ORDER BY ID) - 1 ) / 3 + 1 AS GroupNr
FROM Table
) T2 ON T1.GroupNr = T2.GroupNr
When I perform "SELECT * FROM table" I got results like below:
ID Date Time Type
----------------------------------
60 03/03/2013 8:55:00 AM 1
60 03/03/2013 2:10:00 PM 2
110 17/03/2013 9:15:00 AM 1
67 24/03/2013 9:00:00 AM 1
67 24/03/2013 3:05:00 PM 2
as you see each ID has a transaction Type 1 and 2 in the same Date
except ID 110 HAS only Type 1
So how could I just get result like this:
ID Date Time Type
----------------------------------
110 17/03/2013 9:15:00 AM 1
as only one record are returned from the first result
Change the partition definition (partition by id,date) according to your needs
select *
from (select t.*
,count(*) over (partition by id,date) as cnt
from mytable t
) t
where t.cnt = 1
;
You can use this:
select * from my_table t
where exists (
select 1 from my_table
where id = t.id
group by id
having count(*) = 1
)
If you want only type 1, then compare the minimum and maximum values. I prefer window functions:
select t.*
from (select t.*, min(type) over (partition by id) as mintype,
max(type) over (partition by id) as maxtype
from t
) t
where mintype = maxtype and mintype = 1;
If you want only records of the same type (and not specifically type = 1), then remove that condition.
If you want only records on the same day, then include the date in the partition by.
Under some circumstances, not exists can be faster:
select t.*
from t
where not exists (select 1 from t t2 where t2.id = t.id and t2.type <> 1);
I am having a table test having data as follows and I want to delete the trsid 124 and I have millions entry in my DB it is just a scenarion. Concept is to delete the duplicate entry from the table
--------------------------------------------
TrsId | ID | Name |
--------------------------------------------
123 | 1 | ABC |
124 | 1 | ABC |
I am trying something like
delete from test
select T.* from
(
select ROW_NUMBER() over (partition by ID order by name) as r,
Trsid,
ID,
name
from test
) t
where r = 2
Even if I update the query which is Ok for me
update test set id=NULL
select T.* from
(
select ROW_NUMBER() over (partition by ID order by name) as r,
Trsid,
ID,
name
from test
) t
where r = 2
But if i run both this query it deletes all the records from table test. And if i update it update both the records.
I dont know what I am doing wrong here
WITH cte AS
(
SELECT ROW_NUMBER() OVER(PARTITION by ID ORDER BY name) AS Row
FROM test
)
DELETE FROM cte
WHERE Row > 1
Use the below query.
;WITH cte_1
AS (SELECT ROW_NUMBER() OVER(PARTITION BY ID,NAME ORDER BY TrsId ) Rno,*
FROM YourTable)
DELETE
FROM cte_1
WHERE RNO>1
WITH cte_DUP AS (
SELECT * FROM (
select <col1,col2,col3..coln>, row_number()
over(partition by <col1,col2,col3..coln>
order by <col1,col2,col3..coln> ) rownumber
from <your table> ) AB WHERE rownumber > 1)
DELETE FROM cte_DUP WHERE ROWNUMBER > 1
To find duplicate records we can write like below query,
;WITH dup_val
AS (SELECT a,
b,
Row_number()
OVER(
partition BY a, b
ORDER BY b, NAME)AS [RANK]
FROM table_name)
SELECT *
FROM dup_val
WHERE [rank] <> 1;