Select the non repeating/Distinct value in SQL - sql

I'm trying to select the record based on the distinct id. When i go for 'DISTINCT' it picks the duplicate record and truncates the repeating record and gives me the one left out.
How can i SQL to pick to just that record which isn't repeated ?
INPUT
id
name
age
location
1
a
22
usa
1
a
23
usa
2
b
44
uk
3
e
33
eu
3
f
55
eu
8
k
49
usa
OUTPUT
id
name
age
location
2
b
44
uk
8
k
49
usa

ok , here is how you can do it :
select * from (
select * , count(*) over (partition by id) cn
from tablename
) t
where cn = 1

Try this:
SELECT *
FROM [Input]
WHERE ID IN (
SELECT ID FROM [Input] GROUP BY ID HAVING COUNT(ID) = 1
)

This should achieve the output you're after:
SELECT *
FROM yourtable
WHERE id IN (
SELECT id
FROM yourtable
GROUP BY id
HAVING COUNT(*) = 1)

You can use SQL Common Transaction Expression (CTE) AS FOLLOWS
declare #mytable as table(id int ,name nvarchar(100),age int,location nvarchar(50))
insert into #mytable values
(1,'a',22,'usa'),(1,'a',23,'usa'),(2,'b',44,'uk'),(3,'e',33,'eu'),(3,'f',55,'Tunisia'),('8','k',49,'Palestine')
with
cte1 as(select * from #mytable),
cte2 as (select id, count(1) N from #mytable group by id),
cte3 as (select TA.id,TA.name,TA.age,TA.location from cte1 TA inner join cte2 TB on TA.id=TB.id where TB.N=1)
select * from cte3

Related

MS-SQL max ID with inner join

Can't see the wood for the trees on this and I'm sure it's simple.
I'm trying to return the max ID for a related record in a joined table
Table1
NiD
Name
1
Peter
2
John
3
Arthur
Table2
ID
NiD
Value
1
1
5
2
2
10
3
3
10
4
1
20
5
2
15
Max Results
NiD
ID
Value
1
4
20
2
5
15
3
3
10
You can use row_number() for this:
select NiD, ID, Value
from (select t2.*,
row_number() over (partition by NiD order by ID desc) as seqnum
from table2 t2
) t2
where seqnum = 1;
As the question is stated, you do not need table1, because table2 has all the ids.
This is how I'd do it, I think ID and Value will be NULL when Table2 does not have a corresponding entry for a Table1 record:
SELECT NiD, ID, [Value]
FROM Table1
OUTER APPLY (
SELECT TOP 1 ID, [Value]
FROM Table2
WHERE Table1.NiD = Table2.NiD
ORDER BY [Value] DESC
) AS Top_Table2
CREATE TABLE Names
(
NID INT,
[Name] VARCHAR(MAX)
)
CREATE TABLE Results
(
ID INT,
NID INT,
VALUE INT
)
INSERT INTO Names VALUES (1,'Peter'),(2,'John'),(3,'Arthur')
INSERT INTO Results VALUES (1,1,5),(2,2,10),(3,3,10),(4,1,20),(5,2,15)
SELECT a.NID,
r.ID,
a.MaxVal
FROM (
SELECT NID,
MAX(VALUE) as MaxVal
FROM Results r
GROUP BY NID
) a
JOIN Results r
ON a.NID = r.NID AND a.MaxVal = r.VALUE
ORDER BY NID
Here's what I have used in similar situations, performance was fine, provided that the data set wasn't too large (under 1M rows).
SELECT
table1.nid
,table2.id
,table2.value
FROM table1
INNER JOIN table2 ON table1.nid = table2.nid
WHERE table2.value = (
SELECT MAX(value)
FROM table2
WHERE nid = table1.nid)
ORDER BY 1

SQL select top if columns are same

If I have a table like this:
Id StateId Name
1 1 a
2 2 b
3 1 c
4 1 d
5 3 e
6 2 f
I want to select like below:
Id StateId Name
4 1 d
5 3 e
6 2 f
For example, Ids 1,3,4 have stateid 1. So select row with max Id, i.e, 4.
; WITH CTE AS
(
SELECT *, ROW_NUMBER() OVER(PARTITION BY STATEID ORDER BY ID DESC) AS RN
)SELECT ID, STATEID, NAME FROM CTE WHERE RN = 1
You can use ROW_NUMBER() + TOP 1 WITH TIES:
SELECT TOP 1 WITH TIES
Id,
StateId,
[Name]
FROM YourTable
ORDER BY ROW_NUMBER() OVER (PARTITION BY StateId ORDER BY Id DESC)
Output:
Id StateId Name
4 1 d
6 2 f
5 3 e
Disclaimer: I gave this answer before the OP had specified an actual database, and hence avoided using window functions. For a possibly more appropriate answer, see the reply by #Tanjim above.
Here is an option using joins which should work across most RDBMS.
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT StateId, MAX(Id) AS Id
FROM yourTable
GROUP BY StateId
) t2
ON t1.StateId = t2.StateId AND
t1.Id = t2.Id
The following using a subquery, to find the maximum Id for each of the states. The WHERE clause then only includes rows with ids from that subquery.
SELECT
[Id], [StateID], [Name]
FROM
TABLENAME S1
WHERE
Id IN (SELECT MAX(Id) FROM TABLENAME S2 WHERE S2.StateID = S1.StateID)

using group by in subquery in sql

how to get around this error :
Unable to use an aggregate or a subquery in an expression used in the
GROUP BY list of a GROUP BY clause.
here is my query :
select Id, name,dayA,monthA,yearA,
sum(x) as x,
(select SUM(x) group by month) as total,
from table_A
group by Id,name,monthA,dAyA,yearA, SUM(x)
in other words :
sample data :
id name dayA monthA yearA x
===========================
1 name1 2 3 2016 4
2 name2 2 3 2016 3
3 name1 2 3 2016 2
Expected result :
id name dayA monthA yearA x total
===================================
1 name1 2 3 2016 4 6
2 name2 2 3 2016 3 3
3 name1 2 3 2016 2 6
Thanks in advance
you're query has more problem.
(select SUM(x) group by month) as total, is it from the same table, not likely since column month is not mention inyour group by. When using sub query in a query, you must guaranteed that i will only return one record.
Based on your sample data and expected results...
create table table_A(
id int,
name varchar(25),
dayA int,
monthA int,
yearA int,
x int
)
insert into table_A
values (1,'name1',2,3,2016,4),
(2,'name2',2,3,2016,3),
(2,'name1',2,3,2016,2)
select ta.id, ta.name, ta.dayA, ta.monthA, ta.yearA, ta.x, total.Total from table_A as ta
left join
(select name, sum(x) as Total from table_A group by name) total on ta.name = total.name
group by
ta.id, ta.name, ta.dayA, ta.monthA, ta.yearA, ta.x, total.name, total.Total
May be this is what you want:
select table_A.*, TotalSums.total
from table_A
left join (select name, monthA, dayA, yearA, sum(x) as total from table_A group by name, monthA, dayA, yearA) as TotalSums
on table_A.name = TotalSums.name
and table_A.monthA = TotalSums.monthA
and table_A.dayA = TotalSums.dayA
and table_A.yearA = TotalSums.yearA
order by id
i think this is what you're looking for
select Id, main.name,dayA,main.monthA,main.yearA,
sum(x) as x,
,max(total.total) as total
from table_A as main
join (select SUM(x) total ,name ,monthA,yearA from table_A group by name,monthA,yearA) as total
on main.name = total.name
and main.monthA = total.monthA
and main.yearA = total.yearA
group by Id,main.name,monthA,dAyA,yearA

Second maximum and minimum values

Given a table with multiple rows of an int field and the same identifier, is it possible to return the 2nd maximum and 2nd minimum value from the table.
A table consists of
ID | number
------------------------
1 | 10
1 | 11
1 | 13
1 | 14
1 | 15
1 | 16
Final Result would be
ID | nMin | nMax
--------------------------------
1 | 11 | 15
You can use row_number to assign a ranking per ID. Then you can group by id and pick the rows with the ranking you're after. The following example picks the second lowest and third highest :
select id
, max(case when rnAsc = 2 then number end) as SecondLowest
, max(case when rnDesc = 3 then number end) as ThirdHighest
from (
select ID
, row_number() over (partition by ID order by number) as rnAsc
, row_number() over (partition by ID order by number desc) as rnDesc
) as SubQueryAlias
group by
id
The max is just to pick out the one non-null value; you can replace it with min or even avg and it would not affect the outcome.
This will work, but see caveats:
SELECT Id, number
INTO #T
FROM (
SELECT 1 ID, 10 number
UNION
SELECT 1 ID, 10 number
UNION
SELECT 1 ID, 11 number
UNION
SELECT 1 ID, 13 number
UNION
SELECT 1 ID, 14 number
UNION
SELECT 1 ID, 15 number
UNION
SELECT 1 ID, 16 number
) U;
WITH EX AS (
SELECT Id, MIN(number) MinNumber, MAX(number) MaxNumber
FROM #T
GROUP BY Id
)
SELECT #T.Id, MIN(number) nMin, MAX(number) nMax
FROM #T INNER JOIN
EX ON #T.Id = EX.Id
WHERE #T.number <> MinNumber AND #T.number <> MaxNumber
GROUP BY #T.Id
DROP TABLE #T;
If you have two MAX values that are the same value, this will not pick them up. So depending on how your data is presented you could be losing the proper result.
You could select the next minimum value by using the following method:
SELECT MAX(Number)
FROM
(
SELECT top 2 (Number)
FROM table1 t1
WHERE ID = {MyNumber}
order by Number
)a
It only works if you can restrict the inner query with a where clause
This would be a better way. I quickly put this together, but if you can combine the two queries, you will get exactly what you were looking for.
select *
from
(
select
myID,
myNumber,
row_number() over (order by myID) as myRowNumber
from MyTable
) x
where x.myRowNumber = 2
select *
from
(
select
myID,
myNumber,
row_number() over (order by myID desc) as myRowNumber
from MyTable
) y
where x.myRowNumber = 2
let the table name be tblName.
select max(number) from tblName where number not in (select max(number) from tblName);
same for min, just replace max with min.
As I myself learned just today the solution is to use LIMIT. You order the results so that the highest values are on top and limit the result to 2. Then you select that subselect and order it the other way round and only take the first one.
SELECT somefield FROM (
SELECT somefield from table
ORDER BY somefield DESC LIMIT 2)
ORDER BY somefield ASC LIMIT 1

Help me with my select query

I have this table in sql server 2005:
id student active
1 Bob 1
3 Rob 0
5 Steve 1
7 John 1
8 Mark 0
10 Dave 0
16 Nick 1
My select query returns an active student by a given id.
But I also want to return the ids of prev and next student who are active. If no prev, it will be 0 or null. Same for next.
Example: for id=5, my select would return
id student prev_id next_id
5 steve 1 7
Example: for id=7, my select would return
id student prev_id next_id
7 John 5 16
Example: for id=16, my select would return
id student prev_id next_id
16 Nick 7 0
How do I write this select query?
I have query but I just can't get the prev id correctly. It always returns the first active id.
Thanks
EDIT:
Here is the query I have right now.
select id, student,
(select top 1 id from test where id<7 and active=1) as prev,
(select top 1 id from test where id>7 and active=1) as next
from test where id=7--I used 7 just as an example. it will be a parameter
try something like this
SELECT ID,
Student,
( SELECT TOP 1
ID
FROM dbo.table AS pT
WHERE pT.ID < T.ID And Active = 1
ORDER BY ID DESC
) AS PrevID,
( SELECT TOP 1
ID
FROM dbo.table AS pT
WHERE pT.ID > T.ID And Active = 1
ORDER BY ID
) AS NextID
FROM dbo.table AS T
Working sample
DECLARE #T TABLE (id int, student varchar(10), active bit)
insert #t select
1 ,'Bob', 1 union all select
3 ,'Rob', 0 union all select
5 ,'Steve', 1 union all select
7 ,'John', 1 union all select
8 ,'Mark', 0 union all select
10 ,'Dave', 0 union all select
16 ,'Nick', 1
---- your query starts below this line
declare #id int set #id = 5
select id, student,
isnull((select top(1) Prev.id from #T Prev
where Prev.id < T.id and Prev.active=1
order by Prev.id desc),0) Prev,
isnull((select top(1) Next.id from #T Next
where Next.id > T.id and Next.active=1
order by Next.id),0) Next
from #T T
where id = #id
The ISNULLs are to return 0 when there is no match - NULL would have worked fine but your question has 0 when there is no Next.
You may want to take a look at Common Table Expression, a feature for only SQL Server for recursive queries, you can find a link here
But this sound like homework, and probebly not the right forum to ask it in.
Regards
You could use a nested query. I obviously can't test this out, but you should get the idea.
SELECT id, student ,
(SELECT C1.id FROM students S1 WHERE S1.active = 1 AND S1.id < S.id LIMIT 1) AS beforeActive,
(SELECT C2.id FROM categories S2 WHERE S2.active = 1 AND S2.id > S.id LIMIT 1) AS afterActive
FROM students S
Efficiency wise, I've no idea how well this query will perform
This will give you a little more control, especially since you are paginating.
WITH NumberedSet AS (
SELECT s.id,
s.student,
row_number() OVER (ORDER BY s.id) AS rownum
FROM dbo.students AS s
WHERE s.active = 1
)
SELECT cur.id,
cur.student,
isnull(prv.id,0) AS prev_id,
isnull(nxt.id,0) AS next_id
FROM NumberedSet AS cur
LEFT JOIN NumberedSet AS prv ON cur.rownum - 1 = prv.rownum
LEFT JOIN NumberedSet AS nxt ON cur.rownum + 1 = nxt.rownum
;