Select only one row with same key value from a table - sql

I have this table:
reg_no | cname | no
1 | X | 1
1 | Y | 2
2 | X | 1
2 | Y | 2
What I want to do is to select all that rows but I only want one row for each reg_no when I arrange it in desc (it should only get the row with highest no for each reg_no).
The output should be:
1 Y 2
2 Y 2

Use Row_Number() window function
select Reg_no,C_name,no from
(
select row_number() over(partition by reg_no order by no desc) Rn,*
from yourtable
) A
where rn=1
or ANSI SQL standard will work in sql server 2000. Find the max no in each reg_no then join the result back to the main table.
select A.Reg_no,A.C_name,A.no
from yourtable As A
Inner Join
(
select max(no) As no,Reg_no
from yourtable
group by Reg_No
) As B
on A.No=B.No and A.Reg_No=B.Reg_no

In MSSQL using CROSS APPLY this would be
SELECT DISTINCT
r1.reg_no, r2.cname, r2.no
FROM
table_name r1
CROSS APPLY
(SELECT TOP 1
r.cname, r.no
FROM
table_name r
WHERE r1.reg_no = r.reg_no
ORDER BY r.no DESC) r2

Related

Merging two tables with no unique keys without row number

I have two tables
Table A:
Name
----
Andy
Greg
Table B:
Value
-----
1
2
I want to merge these two tables into one:
Table C:
Result
------
Andy 1
Greg 2
Note:-
without changing the order. I cannot use row numbers as I am using Apache Calcite and it doesn't support that right now.
Is this possible?
WITH X AS
(
SELECT * FROM
(
SELECT NAME AS Val1,
(SELECT Count(*) from #TableA a1 WHERE a1.Name < a2.Name) AS myRowNumber1 FROM #TableA a2
)a1
INNER JOIN
(
SELECT Id AS Val2,
(SELECT Count(*) from #TableB a1 WHERE a1.Id < a2.Id) AS myRowNumber2 FROM #TableB a2
)b1
ON a1.myRowNumber1=b1.myRowNumber2
)
SELECT Val1 +' '+ Val2 AS Result FROM X
You can use Count(*) instead of Row_Number()
OutPut:-
Result
---------
Andy 1
Greg 2
Create a new column as an identifier
SELECT *, ROW_NUMBER() OVER(PARTITION BY NAME ORDER BY NAME) AS id
INTO #NAMES
FROM TABLE1
SELECT *, ROW_NUMBER() OVER(PARTITION BY VALUE ORDER BY VALUE) AS id
INTO #VALUES_TABLE
FROM TABLE2
And then join by the row number that will be called id
SELECT *
FROM #NAMES t1
LEFT JOIN #VALUES_TABLE t2
ON t1.id = t2.id
Calcite does not have a function exactly like Oracle's ROWNUM pseudocolumn but it does have the standard SQL window function ROW_NUMBER(). You can use it as follows:
create table a as select * from (values ('Andy'), ('Greg')) as t (name);
create table b as select * from (values (1), (2)) as t (v);
select *
from (select name, row_number() over () as id from a)
join (select v, row_number() over () as id from b)
using (id);
+----+------+---+
| ID | NAME | V |
+----+------+---+
| 1 | Andy | 1 |
| 2 | Greg | 2 |
+----+------+---+
(2 rows)
If you want deterministic order, you can change over () to, say, over (order by name desc).

sql: sum of highest n values in each group [duplicate]

This question already has answers here:
Using LIMIT within GROUP BY to get N results per group?
(14 answers)
In MySQL, how can I find the sum of the N largest values grouped on a particular column? [duplicate]
(1 answer)
Closed 4 years ago.
I need to find the sum of the n highest values in each group.
With (n=2):
group | points
g1 | 3
g2 | 3
g3 | 4
g1 | 2
g1 | 4
g2 | 5
g2 | 5
g3 | 1
g3 | 2
result
group | sum
g1 | 7
g2 | 10
g3 | 6
sql using join and group
thanks
If your RDBMS supports window function, you can use ROW_NUMBER() to assign a number to each record in the group, ordered by points, and then filter out top 2 records of each group in an outer, aggregated query.
SELECT grp, SUM(points) total
FROM (
SELECT grp, points, ROW_NUMBER() OVER(PARTITION BY grp ORDER BY points DESC) rn
FROM mytable
) x
WHERE rn <= 2
GROUP BY grp
ORDER BY grp
This MySQL 8.0 DB Fiddle with your sample data yields :
| grp | total |
| --- | ----- |
| g1 | 7 |
| g2 | 10 |
| g3 | 6 |
Example dataset:
create table #temp (name varchar(20), value int)
insert into #temp values ('g1',2),('g2',2),('g3',2),('g2',7),
('g3',9),('g1',4),('g2',8),('g3',1),('g1',3),('g1',11)
Another way to handle this issue is to use "cross apply" like in Sql Server below:
--This returns top 2 rows for each group where its value is highest.
SELECT x.*
FROM ( SELECT DISTINCT name FROM #temp ) c
CROSS APPLY ( SELECT TOP 2 * FROM #temp t WHERE c.name = t.name order by value desc ) x
--This returns sum of top 2 value of each group
SELECT x.name, SUM(x.Value) as Total
FROM ( SELECT DISTINCT name FROM #temp ) c
CROSS APPLY ( SELECT TOP 2 * FROM #temp t WHERE c.name = t.name order by value desc ) x
group by x.name
Since your #n value here is not static, and will be changed based on user's choice, you can use dynamic query like below:
declare #n int = 2;
declare #sql nvarchar(max) = 'SELECT x.name, SUM(x.Value) as Total
FROM ( SELECT DISTINCT name FROM #temp ) c
CROSS APPLY ( SELECT TOP '+cast(#n as nvarchar(10))+' * FROM #temp t
WHERE c.name = t.name order by value desc ) x
group by x.name'
exec sp_executesql #sql

SQL, choosing max date and if two results have a max date, choose the one with the max weight

ID | DATE_I | Weight
1 | 10/04/2014 08:13:05 | 10
2 | 02/04/2014 08:13:05 | 15
3 | 08/04/2014 08:13:05 | 10
4 | 13/04/2014 08:13:05 | 12
5 | 13/04/2014 08:13:05 | 10
My SQL request request should give me row 4.
select id, max(DATE_I)
from MyTable m
where m.Weight > (select m2.Weight from MyTable m2 having max(DATE_I));
Try this:
select y.ID, x.maxdate, x.maxweight
from
(
select a.maxdate, Max(b.Weight) as maxweight
from
(
select max(date_I) as maxdate
from mytable
)a
inner join mytable b on a.maxdate = b.date_I
group By a.maxdate
) x inner join mytable y on x.maxweight = y.weight
Demo Here
Order your rows on DATE_I and Weight descending and get the first row.
Sample code for SQL Server.
select top (1) ID, DATE_I, Weight
from mytable
order by DATE_I desc, Weight desc;

Renumber dynamic column without update in SQL Server

I have this data
5 | Batman
5 | Superman
5 | Wonderwomen
6 | Green Lantern
6 | Green Arrow
7 | Cyborg
when I do select query, I want renumber to
1 | Batman
1 | Superman
1 | Wonderwomen
2 | Green Lantern
2 | Green Arrow
3 | Cyborg
thought?
EDIT:
thanks to vittore, so i came up with this solution. I'm not sure if my query is good.
I do ROW_NUMBER() twice. In case my sequence Id is jumping, this query will renumbering perfectly.
WITH cte AS
(
SELECT ROW_NUMBER() OVER(PARTITION BY id ORDER BY id asc) AS CteId
FROM MyTable
)
SELECT
ROW_NUMBER() OVER(PARTITION BY CteId ORDER BY CteId asc) AS RenumberColumn
FROM cte
RANK function is what you are looking for
select RANK() OVER (ORDER BY id), name
from t
Check row_number() and dense_rank() when you reading about it as well.
UPDATE: If you just use rank alone, it will give you not the values you want ( 1 1 1 2 2 3 ), but ranked values ( 1 1 1 4 4 6 )
So in order to get (1 2 3) group, rank and join:
select a.r, t.name from t
inner join (select id, rank() over (order by id asc) r
from t group by id) a
on t.id = a.id
If it's always -4, then:
Select (number-4), name
from table
But I doubt it's that simple.

sql minimum from one column, unique for another column group by a third

I have this query where I'm selecting from three tables
select
min(t.ReminderDt) as 'rem dt',
m.Group_Id, m.AccountNumber
from
ACE_AccsLevelTran t, ACE_AccsLevelMaster m
where
t.MasterAccNumber = m.AccountNumber
group by
m.Group_Id, m.AccountNumber;
This results in:
rem dt | Group_Id| AccountNumber
--------------------------------
2/8/2013 | 3 | 4216985
2/22/2013 | 4 | 4274863
2/7/2013 | 3 | 4366383
2/28/2013 | 4 | 7151712
How do I get the rows for only the minimum dates for 3 and 4 like the result -
2/7/2013 | 3 | 4366383
2/22/2013 | 4 | 4274863
Just remove the account_number from the group by and surround it with min() or max() on the select line:
select min(t.ReminderDt) as 'rem dt', m.Group_Id, min(m.AccountNumber)
from ACE_AccsLevelTran t, ACE_AccsLevelMaster m
where t.MasterAccNumber=m.AccountNumber
group by m.Group_Id
That returns an arbitrary account number. To get the row with the minimum value, the best way is to use row_number():
select *
from (select t.ReminderDt) as 'rem dt', m.Group_Id, m.AccountNumber,
row_number() over (partition by group_id order by reminderdt desc) as seqnum
from ACE_AccsLevelTran t join ACE_AccsLevelMaster m
on t.MasterAccNumber=m.AccountNumber
) t
where seqnum = 1
Also, you should learn ANSI standard JOIN syntax, as used in this query.
If your accountNumber is Unique too you can do it in this way:
Select m.Group_Id ,X.MinReminderDT,m.AccountNumber
from ACE_AccsLevelMaster m join(
select min(t.ReminderDt) as MinReminderDT,t.MasterAccNumber
from ACE_AccsLevelTran t
Group By t.MasterAccNumber) X on X.MasterAccNumber=m.AccountNumber