SQL select columns group by - sql

If I have a table which is of the following format:
ID NAME NUM TIMESTAMP BOOL
1 A 5 09:50 TRUE
1 B 6 13:01 TRUE
1 A 1 10:18 FALSE
2 A 3 12:20 FALSE
1 A 1 05:30 TRUE
1 A 12 06:00 TRUE
How can I get the ID, NAME and NUM for each unique ID, NAME pair with the latest Timestamp and BOOL=TRUE.
So for the above table the output should be:
ID NAME NUM
1 A 5
1 B 6
I tried using Group By but I cannot seem to get around that either I need to put an aggregator function around num (max, min will not work when applied to this example) or specifying it in group by (which will end up matching on ID, NAME, and NUM combined). Both as far as I can think will break in some case.
PS: I am using SQL Developer (that is the SQL developed by Oracle I think, sorry I am a newbie at this)

If you're using at least SQL-Server 2005 you can use the ROW_NUMBER function:
WITH CTE AS
(
SELECT ID, NAME, NUM,
RN = ROW_NUMBER()OVER(PARTITION BY ID, NAME ORDER BY TIMESTAMP DESC)
FROM Table
WHERE BOOL='TRUE'
)
SELECT ID, NAME, NUM FROM CTE
WHERE RN = 1
Result:
ID NAME NUM
1 A 5
1 B 6
Here's the fiddle: http://sqlfiddle.com/#!3/a1dc9/10/0

select t1.* from table as t1 inner join
(
select NAME, NUM, max(TIMESTAMP) as TIMESTAMP from table
where BOOL='TRUE'
) as t2
on t1.name=t2.name and t1.num=t2.num and t1.timestamp=t2.timestamp
where t1.BOOL='TRUE'

select t1.*
from TABLE1 as t1
left join
TABLE1 as t2
on t1.name=t2.name and t1.TIMESTAMP>t2.TIMESTAMP
where t1.BOOL='TRUE' and t2.id is null
should do it for you.

Related

How do i select all columns, plus the result of the sum

I have this select:
"Select * from table" that return:
Id
Value
1
1
1
1
2
10
2
10
My goal is create a sum from each Value group by id like this:
Id
Value
Sum
1
1
2
1
1
2
2
10
20
2
10
20
I Have tried ways like:
SELECT Id,Value, (SELECT SUM(Value) FROM Table V2 WHERE V2.Id= V.Id GROUP BY IDRNC ) FROM Table v;
But the is not grouping by id.
Id
Value
Sum
1
1
1
1
1
1
2
10
10
2
10
10
Aggregation aggregates rows, reducing the number of records in the output. In this case you want to apply the result of a computation to each of your records, task carried out by the corresponding window function.
SELECT table.*, SUM(Value) OVER(PARTITION BY Id) AS sum_
FROM table
Check the demo here.
Your attempt looks correct.
Can you try the below query :
It works for me :
SELECT Id, Value,
(SELECT SUM(Value) FROM Table V2 WHERE V2.Id= V.Id GROUP BY ID) as sum
FROM Table v;
You can do it using inner join to join with selection grouped by id :
select t.*, sum
from _table t
inner join (
select id, sum(Value) as sum
from _table
group by id
) as s on s.id = t.id
You can check it here
Your select is ok if you adjust it just a little:
SELECT Id,Value, (SELECT SUM(Value) FROM Table V2 WHERE V2.Id= V.Id GROUP BY IDRNC ) FROM Table v;
GROUP BY IDRNC is a mistake and should be GROUP BY ID
you should give an alias to a sum column ...
subquery selecting the sum does not have to have self table alias to be compared with outer query that has one (this is not a mistake - works either way)
Test:
WITH
a_table (ID, VALUE) AS
(
Select 1, 1 From Dual Union All
Select 1, 1 From Dual Union All
Select 2, 10 From Dual Union All
Select 2, 10 From Dual
)
SELECT ID, VALUE, (SELECT SUM(VALUE) FROM a_table WHERE ID = v.ID GROUP BY ID) "ID_SUM" FROM a_table v;
ID VALUE ID_SUM
---------- ---------- ----------
1 1 2
1 1 2
2 10 20
2 10 20

how to return the max seqence record

I've a table that stores the historical data, what i'm trying to do is trying to capture the max seq record. i can do that, but i need to include the tr_type, then i'll use the outupt to join with another table. below is ex of my data
CLM_NO SEQ SUB TR_TYPE
12345 1 1 50
12345 1 2 50
12345 2 1 60
12345 2 2 60
i want to return only the last row
You can try to use exists and correlated subquery
SELECT *
FROM T t1
WHERE exists(
SELECT 1
FROM T tt
GROUP BY tt.CLM_NO
HAVING MAX(tt.SEQ) = t1.SEQ AND MAX(tt.SUB) = t1.SUB
)
EDIT
You can try to use ROW_NUMBER window function.
SELECT * FROM (
SELECT *,ROW_NUMBER() OVER(PARTITION BY CLM_NO ORDER BY TRAN_SEQ DESC,TRAN_SUB DESC) rn
FROM TBL t1
)t1
where rn = 1

How to select unique records by ORACLE

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);

Add a column with the max value of the group

I want to add an extra column, where the max values of each group (ID) will appear.
Here how the table looks like:
select ID, VALUE from mytable
ID VALUE
1 4
1 1
1 7
2 2
2 5
3 7
3 3
Here is the result I want to get:
ID VALUE max_values
1 4 7
1 1 7
1 7 7
2 2 5
2 5 5
3 7 7
3 3 7
Thank you for your help in advance!
Your previous questions indicate that you are using SQL Server, in which case you can use window functions:
SELECT ID,
Value,
MaxValue = MAX(Value) OVER(PARTITION BY ID)
FROM mytable;
Based on your comment on another answer about first summing value, you may need to use a subquery to actually get this:
SELECT ID,
Date,
Value,
MaxValue = MAX(Value) OVER(PARTITION BY ID)
FROM ( SELECT ID, Date, Value = SUM(Value)
FROM mytable
GROUP BY ID, Date
) AS t;
There is no need to use GROUP BY in subselect.
select ID, VALUE,
(select MAX(VALUE) from mytable where ID = t.ID) as MaxValue
from mytable t
Use this query.
SELECT ID
,value
,(
SELECT MAX(VALUE)
FROM GetMaxValue gmv
WHERE gmv.ID = gmv1.ID
GROUP BY ID
) as max_value
FROM GetMaxValue gmv1
ORDER BY ID
Try it with a sub select and group by, then grab the MAX of this group:
select
ID,
VALUE,
(select MAX(VALUE)
from mytable
group by ID
having ID = t.ID
) as max_values
from mytable t
Edit:
I built a SQL fiddle, which shows that my solution works, but also VDohnal is correct and doesn't need the group by, so I'll upvote his answer.

how to detect a faulty sequence column with sql?

I have this table
ID | Seq
------------
A 1
A 2
A 3
B 1
B 2
B 3
B 3 <--duplicate seq where ID=B
C 1
C 2
C 4 <--missing seq id number 3
D 1
D 2
. .
. .
Is there a way to detect if/when there is an error in the logic of the Seq column, specifically if there are jumps and/or duplicates.
try this:
this should work both in sql server as well as Oracle
select ID,seq
from(
select ID,seq,
row_number() over (partition by id order by seq ) rn
from t_seq)a
where a.seq<>a.rn
SQL fiddle demo for SQL server
SQL Fiddle demo for Oracle
These are both SQL agnostic so should work in just about any rdbms.
This will check for a break in the sequence:
select t1.id, t1.seq
from t_seq t1
where
t1.seq <> 1
and not exists (
select *
from t_seq t2
where t2.id = t1.id
and t2.seq = t1. seq - 1
)
This will check for duplicates:
select t1.id, t1.seq
from mytable t1
group by t1.id, t1.se1
having count(*) > 1
To get the duplicates you can use the following T-SQL.
SELECT ID, Seq FROM MyTable GROUP BY ID, Seq HAVING COUNT(Seq) > 1
Edit
To find out the missing sequence numbers I have updated the code provided by njr101 to follows:
SELECT ID, Seq FROM MyTable t1 WHERE ID IN (
SELECT ID FROM MyTable
GROUP BY ID
HAVING COUNT(DISTINCT Seq) <> MAX(Seq)
) AND t1.seq <> 1 AND NOT EXISTS (
SELECT * FROM MyTable t2 WHERE t2.id=t1.id AND t2.seq = t1.seq - 1
)
ORDER BY ID
The first sub query counts the number of distinct rows for that ID (ignores duplicates). If that number is the same is the maximum number contained in the result set, the values should be fine for that ID. If it is not equal, the results will be available in the sub query.
The second part (with the help of njr101's query), filters the result set to only contain the last ID and seq where missing values should be inserted. Results below:
My Data
=========
A 1
A 2
A 3
A 20 <--- Missing (displayed in results)
B 1
B 2
B 3
B 3
B 4
C 1
C 2
C 4 <--- Missing (displayed in results)
C 5
C 15 <--- Missing (displayed in results)
C 16
Results
=======
A 20
C 4
C 15