I have a table like this
Id scid name namesuffix nameId namesuffixid fullname
--------------------------------------------------------
1 1 a a 100 100 a
2 1 a b 100 101 ab
3 1 b c 101 102 abc
4 1 c d 102 103 abcd
5 2 e e 104 104 e
6 2 e f 104 105 ef
7 2 f g 105 106 efg
8 3 i i 107 107 i
9 3 i j 107 108 ij
10 3 j k 108 109 ijk
11 3 k l 109 110 ijkl
12 3 l m 110 111 ijklm
for each scid (group by scid)
select firstRow fullName
Last row fullName
Expected output
id scid fullname
-------------------
1 1 a
4 1 abcd
5 2 e
7 2 efg
8 3 i
12 3 ijklm
I tried first_value and last_value analytic functions, but the rows are repeating, didn't get expected result.
Any help appreciated.
Another option is to use ROW_NUMBER() and COUNT
select
id, scid, fullname
from (
select
*, row_number() over (partition by scid order by id) rn
, count(*) over (partition by scid) cnt
from
myTable
) t
where
rn = 1
or rn = cnt
You could use FIRST_VALUE and LAST_VALUE as you proposed:
SELECT scid,
FIRST_VALUE(id) OVER(PARTITION BY scid ORDER BY id
ROWS UNBOUNDED PRECEDING) AS id,
FIRST_VALUE(fullname) OVER(PARTITION BY scid ORDER BY id
ROWS UNBOUNDED PRECEDING) AS fullname
FROM tab_name
UNION
SELECT scid,
LAST_VALUE(id) OVER(PARTITION BY scid ORDER BY id
RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS id,
LAST_VALUE(fullname) OVER(PARTITION BY scid ORDER BY id
RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS fullname
FROM tab_name
ORDER BY scid, id;
Demo
There are other ways to do this without window funtions:
select t.*
from t join
(select min(id) as min_id, max(id) as max_id
from t
group by sc_id
) tt
on t.id in (min_id, max_id);
I only suggest this because there are many ways to do what you want. If performance is an issue, you may want to experiment with different methods.
Related
I would like to find most frequent code within CodeID which is in same code_group from a table.
For example, from original table
ID CodeID Name Code Code_group
1 1 A 101 0
2 1 A 102 0
3 1 B 102 0
4 2 C 201 0
5 2 C 201 0
6 2 D 202 0
7 2 E 202 0
8 3 F 101 1
9 3 G 103 1
10 3 G 104 1
11 3 G 104 1
I want output like the below.
ID CodeID Name Code Code_group Selected_code
1 1 A 101 0 102
2 1 A 102 0 102
3 1 B 102 0 102
4 2 C 201 0 NULL
5 2 C 201 0 NULL
6 2 D 202 0 NULL
7 2 E 202 0 NULL
8 3 F 101 1 104
9 3 G 103 1 104
10 3 H 104 1 104
11 3 H 104 1 104
Even though code of 8th ID is same in CodeID: 1,it is not in the same Code_group.
So For CodeID: 1, Selected_code would be 102.
it must be counted within exactly same Code_group.
=======================================
I have tried it like the below. I should not use ID for this one.
From TableA
with m as
(
select
CodeID,
Name,
Code,
Code_group,
cnt,
Selected_code = ROW_NUMBER() over (partition by Code_group order by cnt desc)
from( select CodeID, Name, Code,Code_group
,count(*) over (partition by Code,CodeID) as cnt from tableA
group by CodeID, Name, Code, Code_group,
) as t
group by CodeID,
Name,
Code,
Code_group, cnt
)
select a.CodeID,
a.Name,
a.Code,
a.Code_group, b.Code as Selected_code, cnt
from(select
CodeID,
Name,
Code,
Code_group,Selected_code,
cnt
from m) as a left outer join
(select CodeID,
Name,
Code,
Code_group,Selected_code,
cnt
from m where selected_Code=1) as b on a.CodeID = b.CodeID and a.Code_Group = b.Code_Group
order by a.CodeID, a.Code_Group
The problem of this is
With statment makes my table distinct. It shows only one row if there is exactly same data such as ID 1,2.
Also, I cannot make NULL if there is exactly same frequencies.
What should I add to get my desired output?
Or is there any better approach for this?
CTE cte find the highest frequency code by Code_group and CodeID using dense_rank()
CTE selected check for any Code with same frequency and exclude them.
Final query just select from the original table and LEFT JOIN the selected
with
cte as
(
select Code_group, CodeID, Code
from
(
select Code_group, CodeID, Code,
r = dense_rank() over (partition by Code_Group, CodeID
order by count(*) desc)
from tableA
group by Code_group, CodeID, Code
) c
where c.r = 1
),
selected as
(
select Code_group, CodeID, Code
from
(
select Code_group, CodeID, Code,
cnt = count(*) over (partition by Code_group, CodeID)
from cte
) s
where s.cnt = 1
)
select a.*,
Selected_Code = s.Code
from tableA a
left join selected s on a.Code_Group = s.Code_Group
and a.CodeID = s.CodeID;
db<>fiddle demo
I am having some trouble with the below query. I do understand I need to group by ID and Category, but I only want to group by ID while keeping the rest of the columns based on Rank being max. Is there a way to only group by certain columns?
select ID, Category, max(rank)
from schema.table1
group by ID
Input:
ID Category Rank
111 3 4
111 1 5
123 5 3
124 7 2
Current Output
ID Category Rank
111 3 4
111 9 1
123 5 3
124 7 2
Desired Output
ID Category Rank
111 1 5
123 5 3
124 7 2
You can use:
select *
from table1
where (id, rank) in (select id, max(rank) from table1 group by id)
Result:
ID CATEGORY RANK
---- --------- ----
111 1 5
123 5 3
124 7 2
Or you can use the ROW_NUMBER() window function. For example:
select *
from (
select *,
row_number() over(partition by id order by rank desc) as rn
from table1
) x
where rn = 1
See running example at db<>fiddle.
You can try using - row_number()
select * from
(
select ID, Category,rank, row_number() over(partition by id order by rank desc) as rn
from schema.table1
)A where rn=1
For example, N is 10 and a table looks like
id
1
2
3
4
5
6
7
10
11
12
13
108
109
111
112
113
Need to find first N rows that have unique value with mod(id, N).
Expected result is
mod10
1
2
3
4
5
6
7
10
108
109
I've tried something like
select *
from
(
select id, id % 10 as seq_id
from accounts order by id
) as s1
group by s1.seq_id limit 10;`
but not working.
You can use window function here -
SELECT id
FROM (SELECT id, ROW_NUMBER() OVER(PARTITION BY id % 10 ORDER BY id) RN
FROM table_name
) X
WHERE RN = 1
ORDER BY id
You can try the below one - using row_number()
DEMO
with cte as
(
select id, row_number() over(partition by seq_id order by id) as rn
from
(
select id, id % 10 as seq_id from tablename
)A
)
select id from cte where rn=1 order by id
OUTPUT:
id
1
2
3
4
5
6
7
10
108
109
How to get the max value order of each customer ?
select num, max(sum(paid*quantity))
from orders join
pizza
using (order#)
group by customer#;
table
num orderN price
-------- --- -------
1 109 30
1 118 25
3 101 30
3 115 27
4 107 23
5 100 17
5 129 16
output req-
num Pnum price
-------- --- -------
1 109 30
3 101 30
4 107 23
5 100 17
You want to select the record having the highest price in each group of nums.
If your RDBMS supports window functions, that's straight forward with ROW_NUMBER() :
SELECT num, pnum, price
FROM (
SELECT t.*, ROW_NUMBER OVER(PARTITION BY num ORDER BY price DESC) rn
FROM mytable t
) x
WHERE rn = 1
Else, you can take the following approach, that uses a NOT EXISTS condition with a correlated subquery to ensure that the record being joined in the one with the highest price for the current num :
SELECT num, pnum, price
FROM mytable t
WHERE NOT EXISTS (
SELECT 1 FROM mytable t1 WHERE t1.num = t.num AND t1.price > t.price
)
I have different versions of the charges in a table. I want to grab and sum the last charge grouped by Type.
So I want to add 9.87, 9.63, 1.65.
I want the Parent ID , sum(9.87 + 9.63 + 1.65) as the results of this query.
We use MSSQL
ID ORDER CHARGES TYPE PARENT ID
1 1 6.45 1 1
2 2 1.25 1 1
3 3 9.87 1 1
4 1 6.54 2 1
5 2 5.64 2 1
6 3 0.84 2 1
7 4 9.63 2 1
8 1 7.33 3 1
9 2 5.65 3 1
10 3 8.65 3 1
11 4 5.14 3 1
12 5 1.65 3 1
WITH recordsList
AS
(
SELECT Type, Charges,
ROW_NUMBER() OVER (PArtition BY TYPE
ORDER BY [ORDER] DESC) rn
FROM tableName
)
SELECT SUM(Charges) totalCharge
FROM recordsLIst
WHERE rn = 1
SQLFiddle Demo
Use row_number() to identify the rows to be summed, and then sum them:
select SUM(charges)
from (select t.*,
ROW_NUMBER() over (PARTITION by type order by id desc) as seqnum
from t
) t
where seqnum = 1
Alternatively you could use a window aggregate MAX():
SELECT SUM(Charges)
FROM (
SELECT
[ORDER],
Charges,
MaxOrder = MAX([ORDER]) OVER (PARTITION BY [TYPE])
FROM atable
) s
WHERE [ORDER] = MaxOrder
;
SELECT t.PARENT_ID, SUM(t.CHARGES)
FROM dbo.test73 t
WHERE EXISTS (
SELECT 1
FROM dbo.test73
WHERE [TYPE] = t.[TYPE]
HAVING MAX([ORDER]) = t.[ORDER]
)
GROUP BY t.PARENT_ID
Demo on SQLFiddle