How to get an index of different category returned by "order by" sql in oracle? - sql

We can easily get a sql result as following:
SQL>select Name, Value from table order by Name;
Name Value
------------
A 1
A 2
B 1
C 5
C 6
C 7
However, is there a way to link the name to a number so that an index of different names can be formed? Suppose we don't know how many different names are in the table and don't know what they are.
Name Value idx
-----------------
A 1 0
A 2 0
B 1 1
C 5 2
C 6 2
C 7 2

This can easily be done using a window function:
select Name,
Value,
dense_rank() over (order by name) - 1 as idx
from table
order by Name;

Related

SQL reset row_number when previous id column null

This is hard to explain so I will give an example.
I need SQL (ms server), I assume its with row_number over partition but can't get it to work.
I have this table:
ID
PreviousID
Data
1
a
2
1
b
3
2
c
4
d
5
4
e
6
f
I want these results:
ID
NewID
Data
1
1
a
2
1
b
3
1
c
4
2
d
5
2
e
6
3
f
And another with just the new IDs of each sequence:
NewID
Data
1
a
2
d
3
f
Instead of a row number new id, it could also have the first id of the sequence, whatever is easier, as long as it identifies the sequence.
Seems you want a windowed COUNT of rows where the value of PreviousID is NULL.
SELECT ID,
COUNT(CASE WHEN PreviousID IS NULL THEN 1 END) OVER (ORDER BY ID) AS NewID,
Data
FROM dbo.YourTable;

Finding adjacent column values from the last non-null value of a certain column in Snowflake (SQL) using partition by

Say I have the following table:
ID
T
R
1
2
1
3
Y
1
4
1
5
1
6
Y
1
7
I would like to add a column which equals the value from column T based on the last non-null value from column R. This means the following:
ID
T
R
GOAL
1
2
1
3
Y
1
4
Y
3
1
5
4
1
6
Y
4
1
7
6
I do have many ID's so I need to make use of the OVER (PARTITION BY ...) clause. Also, if possible, I would like to use a single statement, like
SELECT *
, GOAL
FROM TABLE
So without any extra select statement.
T is in ascending order so just null it out according to R and take the maximum looking backward.
select *,
max(case when R is not null then T end)
over (
partition by id
order by T
rows between unbounded preceding and 1 preceding
) as GOAL
from TBL
http://sqlfiddle.com/#!18/c927a5/5

Fast inclusion of the previous value of another type

I have a table of the following structure:
Ordinal Type
1 A
2 B
3 A
4 B
5 B
6 B
7 A
There are two types and the order according to the ordinal matters. I want the following result:
Ordinal Type Last_A
1 A 1
2 B 1
3 A 3
4 B 3
5 B 3
6 B 3
7 A 7
The new column Last_A should contain the last seen Ordinal for which the Type = A, where last is relative to the order of the Ordinal. There may be an arbitrary number of B-rows before another A-row. Is there a performance efficient way of achieving this result? Using a cursor would easily achieve the desired result, but is not feasible due to the large amount of rows I work with.
You can use a conditional cumulative max():
select t.*,
max(case when t.type = 'A' then ordinal end) over (order by ordinal) as last_A
from t;

Get duplicate on single column after distinct across multiple columns in SQL

I have a table that looks like this:
name | id
-----------
A 1
A 1
B 2
C 1
D 3
D 3
F 2
I want to return id's 1 and 2 because they are duplicate on names. I don't want to return 3, because it is distinct for D 3.
Basically, I'm thinking of doing a query to first get a distinct pairing, so the above reduces to
name | id
-----------
A 1
B 2
C 1
D 3
F 2
And then doing a duplicate find on the id column. However, I'm struggling to find the correct syntax to construct that query.
You should be able to get the result you want by using a GROUP BY along with a HAVING clause that counts the distinct names. The HAVING clause will filter for those ids that have more than one distinct name:
select id
from Table1
group by id
having count(distinct name) > 1
Here is a demo

Assigning row number according to the Column value SQL Server?

I have a table like this in SQL server 2014:
name
a
a
b
b
b
c
d
d
d
I want to create another column that is S.No. , but serial number value will be assigned according to name column. If name occurs 2 times the value of s.no. will be 1 and 2.If d is 3 times than value for d will be 1,2 and 3 and than again counter will start with 1 for e. so the table will be like:
name S.no.
a 1
a 2
b 1
b 2
b 3
c 1
d 1
d 2
d 3
Any solution? thanks for the help.
Use ROW_NUMBER():
SELECT name, ROW_NUMBER() OVER (PARTITION BY name ORDER BY (SELECT 1)) [S.no.]
FROM T
Just in another way by using Count()
select
Name,
Count(1) over (partition by Name ORDER BY Name ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as Slno
from MyTable