Extract Max single upper character from table in oracle - sql

I have test input table
-----------------------
RN | IDs
1 | Az
2 | Azz
3 | B
4 | C
5 | a
6 | e
--------------------
I need Output
----------
RN | IDs
4 | C
I need to get Id which is in UPPER case and single(length 1) also that ID should max in sequence. Like in this example C is the output.
Because Size is 1 , case is UPPER and MAX in sequence.
Can you please help me here.

The first step is identifying the ids values you want to consider. One way it to check the length and the character range:
where length(ids) = 1
and ids between 'A' and 'Z'
which makes some assumptions about your character set, or use a regular expression which also makes some assumptions:
where regexp_like(ids, '^[A-Z]$')
or preferably one which doesn't, using a class instead of a fixed range:
where regexp_like(ids, '^[[:upper:]]$')
With your data any of those give you two rows, for B and C.
You then need to find the row with the maximum ids value. You could do a self-join which is a bit wasteful; or use a subquery that calculates a ranking column and then filter on that:
select rn, ids
from (
select rn, ids, rank() over (order by ids desc) as rnk
from your_table
where regexp_like(ids, '^[[:upper:]]$')
)
where rnk = 1;
RN IDS
---------- ---
4 C
or you could use a variant of the max() function with last to do it in one step:
select max(rn) keep (dense_rank last order by IDs) as rn, max(ids)
from your_table
where regexp_like(ids, '^[[:upper:]]$');
RN MAX
---------- ---
4 C
You haven't said what should happen if there is a tie, e.g. two rn values with C. The first of those approaches will show you both - but could be modified to only show one, if you can specify which you want to see. The second will only show you one, and which is indeterminate at the moment as there is no information in the order by on how to break the tie.

Try this:
SELECT MAX(RN) FROM test
WHERE LENGTH(ID)=1 AND (UNICODE(ID) != UNICODE(LOWER(ID))
GROUP BY ID;

Use the ASCII Function
select max(RN) as MAX_ID from yourTableName t1
where length(t1.IDs)=1 and ascii(IDs) between ascii('A') and ascii('Z');

You can do it in this way, enjoy :)
select h.ID, h.DESC
from test_table h
where length(h.DESC) = 1
and upper(h.DESC) = h.DESC
and h.ID = (select MAX(y.ID)
from test_table y
where length(y.DESC) = 1
and upper(y.DESC) = y.DESC)

It's enough to filter out length(IDs)=1 firstly, and ordering with respect to decode(upper(IDs),IDs,0,1), IDs desc
select RN , IDs
from
(
select t.*,
row_number() over (order by decode(upper(IDs),IDs,0,1), IDs desc )
as rn2
from t
where length(IDs)=1
)
where rn2 = 1;
RN IDS
----- -----
4 C
Rextester Demo

Related

BigQuery Standard SQL - Cumulative Count of (almost) Duplicated Rows

With the following data:
id
field
eventTime
1
A
1
1
A
2
1
B
3
1
A
4
1
B
5
1
B
6
1
B
7
For visualisation purposes, I would like to turn it into the below. Consecutive occurrences of the same field value essentially get aggregated into one.
id
field
eventTime
1
Ax2
1
1
B
3
1
A
4
1
Bx3
5
I will then use STRING_AGG() to turn it into "Ax2 > B > A > Bx3".
I've tried using ROW_NUMBER() to count the repeated instances, with the plan being to utilise the highest row number to modify the string in field, but if I partition on eventTime, there are no consecutive "duplicates", and if I don't partition on it then all rows with the same field value are counted - not just consecutive ones.
I though about bringing in the previous field with LAG() for a comparison to reset the row count, but that only works for transitions from one field value to the other and is a problem if the same field is repeated consecutively.
I'm been struggling with this to the point where I'm considering writing a script that just CASE WHENs up to a reasonable number of consecutive hits, but I've seen it get as high as 17 on a given day and really don't want to be doing that!
My other alternative will just be to enforce a maximum number of field values to help control this, but now I've started this problem I'd quite like to solve it without that, if at all possible.
Thanks!
Consider below
select id,
any_value(field) || if(count(1) = 1, '', 'x' || count(1)) field,
min(eventTime) eventTime
from (
select id, field, eventTime,
countif(ifnull(flag, true)) over(partition by id order by eventTime) grp
from (
select id, field, eventTime,
field != lag(field) over(partition by id order by eventTime) flag
from `project.dataset.table`
)
)
group by id, grp
# order by eventTime
If applied to sample data in your question - output is
Just use lag() to detect when the value of field changes. You can now do that with qualify:
select t.*
from t
where 1=1
qualify lag(field, 1, '') over (partition by id order by eventtime) <> field;
For your final step, you can use a subquery:
select id, string_agg(field, '->' order by eventtime)
from (select t.*
from t
where 1=1
qualify lag(field, 1, '') over (partition by id order by eventtime) <> field
) t
group by id;

ORACLE SQL find row with max date for each grouping

I am trying to write a query which will return only the rows, which time has the greatest value for each id
Table: positions
id time otherCols...
---------- ----------- ----------
1 1
1 2
3 1
1 3
2 1
3 2
Result should look like:
id time otherCols...
---------- ----------- ----------
1 3
2 1
3 2
I tried grouping by id but I don't know how to sort after that and pick only the top result.
You can use MAX(..) KEEP (DENSE_RANK ..) OVER (PARTITION BY ..) analytic function without need of any subquery :
SELECT MAX(time) KEEP (DENSE_RANK LAST ORDER BY time)
OVER (PARTITION BY id) AS time_max,
p.*
FROM positions p
ORDER BY id
Demo
You can use window functions:
select t.*
from (select t.*,
row_number() over (partition by id order by time desc) as seqnum
from t
) t
where seqnum = 1;
An alternative method is a correlated subquery:
select t.*
from t
where t.time = (select max(t2.time) from t t2 where t2.id = t.id);
This is different from the first query in two respects:
If there are duplicate times for an id, then this returns all rows for an id. You can get that behavior using rank() in the first query.
This will not return NULL id values or ids where the time is uniformly NULL. The first query does.

Getting the row with the smallest column value if another column is the same in SQL Server

Id Number Value
------------------
1 6 1
2 6 2
3 9 2
I have a table like this and basically, I need to return the row with the smallest Value if their Number columns are the same, the example result I need is as below:
Id Number Value
-----------------
1 6 1
3 9 2
How do I achieve this in T-SQL?
You could use the rank window function:
SELECT id, number, value
FROM (SELECT id, number, value, RANK() OVER(PARTITION BY number ORDER BY value) AS rk
FROM mytable)
WHERE rk = 1
EDIT:
As noted in the comments, if there is more than one line with the lowest value, using rank would return both. If you want to return just one of them, you should use row_number instead:
SELECT id, number, value
FROM (SELECT id, number, value,
ROW_NUMBER() OVER(PARTITION BY number ORDER BY value) AS rn
FROM mytable)
WHERE rn = 1

SQL: order by two columns and get the firsts rows with equal values in 2-nd column

I have a table sorted by 1, 2 columns. And I need to get the first row from the top and all succeeding rows while their values of 2-nd column is the same as value of the first row.
F.e I have data sample:
select * from sample
order by ID desc, date desc
ID Date
--- ----
45 NULL
44 NULL
40 01/01/10
35 NULL
32 04/05/08
I need to get the first two rows (with id in (45, 44)), because 2-nd row have Date = NULL.
If I'd had data sample:
ID Date
--- ----
45 NULL
44 NULL
40 NULL
35 NULL
32 04/05/08
I will need to get the first 4 rows (with id in (45, 44, 40, 35)).
I can't make query to resolve my issue. I considered about using row_number() and rank(), but I can't adapt they for me purpose.
Thanks a lot for any help!
Based on your description, you can do something like this:
with t as (<your query here>)
select t
from t cross join
(select t.*
from t
order by id desc
limit 1
) tt
order by (case when t.date = tt.date or t.date is null and t2.date is null then 1 else 2 end),
t.id desc;
Well, I concocted something like this, but it doesnt look elegantly.
select *
from (
select *,
sum(rank_date) over (partition by rank_date order by ID desc) as sm
from (
select *
,rank() over(order by DATE desc nulls first) rank_date
,row_number() over(order by ID desc) rank_id
from sample
) ss
) s
where sm = row_number

Getting all fields from table filtered by MAX(Column1)

I have table with some data, for example
ID Specified TIN Value
----------------------
1 0 tin1 45
2 1 tin1 34
3 0 tin2 23
4 3 tin2 47
5 3 tin2 12
I need to get rows with all fields by MAX(Specified) column. And if I have few row with MAX column (in example ID 4 and 5) i must take last one (with ID 5)
finally the result must be
ID Specified TIN Value
-----------------------
2 1 tin1 34
5 3 tin2 12
This will give the desired result with using window function:
;with cte as(select *, row_number(partition by tin order by specified desc, id desc) as rn
from tablename)
select * from cte where rn = 1
Edit: Updated query after question edit.
Here is the fiddle
http://sqlfiddle.com/#!9/20e1b/1/0
SELECT * FROM TBL WHERE ID IN (
SELECT max(id) FROM
TBL WHERE SPECIFIED IN
(SELECT MAX(SPECIFIED) FROM TBL
GROUP BY TIN)
group by specified)
I am sure we can simplify it further, but this will work.
select * from tbl where id =(
SELECT MAX(ID) FROM
tbl where specified =(SELECT MAX(SPECIFIED) FROM tbl))
One method is to use window functions, row_number():
select t.*
from (select t.*, row_number() over (partition by tim
order by specified desc, id desc
) as seqnum
from t
) t
where seqnum = 1;
However, if you have an index on tin, specified id and on id, the most efficient method is:
select t.*
from t
where t.id = (select top 1 t2.id
from t t2
where t2.tin = t.tin
order by t2.specified desc, id desc
);
The reason this is better is that the index will be used for the subquery. Then the index will be used for the outer query as well. This is highly efficient. Although the index will be used for the window functions; the resulting execution plan probably requires scanning the entire table.