How to count by referring date in sql - sql

I have tables like following.
table
product customer surrender_date
A a 2020/5/1
B a 2020/6/1
C b 2019/7/1
D b 2020/8/1
E b 2020/9/1
First I'd like to group by customer
product customer surrender_date
A a 2020/5/1
B a 2020/6/1
Second I'd like to rank by refferring to surrender_date from the newestone
My desired result is like following
product customer surrender_date rank
A a 2020/5/1 2
B a 2020/6/1 1
Therefore My whole desired result is following.
product customer surrender_date rank
A a 2020/5/1 2
B a 2020/6/1 1
C b 2019/7/1 3
D b 2020/8/1 2
E b 2020/9/1 1
Are there any way to achieve this?
As I've never referred to date, If someone has opinion,please let me know.

You can use window functions:
select
t.*,
row_number() over(partition by customer order by surrender_date desc) rnk
from mytable
Notes:
I don't see what the question has to do with aggregation
depending on how you want to handle ties, you might be looking for rank() or dense_rank() instead of row_number()

Related

How to print two columns in ascending order from 2 tables without common column

this question was asked to me in interview i was not able give a answer i tried every solution internet did not gave desired output in oracle sql
input table table A has ID column and table B has Value columns
``table A`
ID(table A) Value(table B)
1 E
2 C
3 B
4 A
5 D
output table wants
ID Value
1 A
2 B
3 C
4 D
5 E
You can both order your numbers table and the letters table and then join the numbers table with the letters table on the row number of the letter table:
SELECT numbers.id, letters.value FROM
(SELECT id
FROM tableA) numbers
JOIN
(SELECT ROW_NUMBER() OVER(ORDER BY value) id, value
FROM tableB ) letters
ON numbers.id = letters.id
ORDER BY numbers.id, letters.id
This simply seems a ROW_NUMBER window function -
SELECT ROW_NUMBER() OVER(ORDER BY value) id, value
FROM your_table
ORDER BY value;
You can match the tables by using ASCII() function as ordering by one of the id or value columns while using a CROSS JOIN such as
SELECT id, value
FROM tableA
CROSS JOIN tableB
WHERE ASCII(value)-64 = id
ORDER BY id
Demo

sql window function not giving me the right output

A B C D
1pm a 1 1
2pm a 2 2
3pm b 1 1
4pm b 2 2
5pm a 3 1
6pm a 4 2
When I do row_number() over (partition by B order by A) as C ., I get the column C. How do I get column D?
You need to assign a group to the "adjacent" values. One simple method is the difference of row numbers:
select a, b,
row_number() over (partition by b, (seqnum_a - seqnum_ab) order by a) as d
from (select t.*,
row_number() over (order by a) as seqnum_a,
row_number() over (partition by b order by a) as seqnum_ab
from t
) t;
The difference of row numbers is one solution to some types of gaps-and-islands problems (basically what you are asking for). Why it works is a little tricky to explain. I find that if someone sees the results of the subquery, they will usually get why the difference identifies the adjacent rows.

How to select a dynamic rank value?

I have a table of companies and another of employees and the dates they joined the company. I am able to get the 5 most recent hires for each company as shown here. Now, I'd like to only show rank <= 3 for Company A, rank <= 8 for Company B and an unlimited number for Company C. 3, 8 and -1 are stored as the "max" column in the company table. How do I dynamically select the max in this case?
You basically want:
SELECT * -- choose the columns you want here
FROM (SELECT e.*, c.max,
row_number() over (partition by company order by joined desc) as rank
FROM employees e JOIN
companies c
on e.company = c.pk
) e
WHERE rank < max or max = -1

Get every second row as a result table in t-sql

I'm looking for a t-sql script that returns a list, that shows every second value from a grouping from Table1.
For example I have the following data (Table1) and want the desired result-list:
Table1:
Customer Quantity
A 5
A 8 (*)
B 3
B 5 (*)
B 11
C 7
D 4
D 23 (*)
Desired retult-list:
Customer Quantity
A 8
B 5
D 23
I think about doing something something with 'select distinct and left outer join', but I can't get it to work. Possibly I need an row numbering, but can't figure out how to do it. Anyone can help me?
Beneath is the script I used to make and fill Table1:
CREATE TABLE Table1
(Customer nvarchar(1) NULL,
Quantity int NOT NULL);
INSERT INTO Table1(Customer,Quantity)
VALUES
('A',5),
('A',8),
('B',3),
('B',5),
('B',11),
('C',7),
('D',4),
('D',23);
This can be done quite easily using the row_number window function:
SELECT customer, quantity
FROM (SELECT customer, quantity,
ROW_NUMBER() OVER (PARTITION BY customer
ORDER BY quantity ASC) AS rn
FROM table1) t
WHERE rn = 2
You can use ROW_NUMBER and a CTE:
WITH data AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Customer ORDER BY Quantity) rn
FROM #Table1
)
SELECT Customer, Quantity
FROM data
WHERE rn = 2
How it works:
Using ROW_NUMBER() will assign a sequential number to each row based on what's specified in OVER (). In OVER i specify to PARTITION the rows on customer, that means each group of data on same customer will be numberered separately. Then ORDER BY Quantity mean it should order the data based on quantity for each customer - so i can get the 2nd row for each customer ordered by quantity.

Top 3 Max entries for a Combination which a condition

I am new to sql side. so if this questoin sound very easy then please spare me. I have a 4 coloumns in a sql table.Let say A,B,C,D . For any BC combination I may get any number of rows. I need to get at max 3 rows (which inturn give me 3 unique value of A for that BC ombination) for these selected rows i should have Top 3 Max value of D. As compare to other entries for that BC combination.
So there can be any number of BC combination so the above logic should imply to all of them.
Most databases support ranking functions. With these, you can do what you want as follows:
select A, B, C, D
from (select t.*,
row_number() over (partition by B, C order by D desc) as seqnum
from t
) t
where seqnum <= 3
order by B, C, D desc
The row_number() function creates a sequencial number. This number starts at "1" in very B,C group, and is ordered by the value of D descending.