select only columns with values not matching between two rows - sql

Is it possible to get only columns which have different values in SQL SERVER?
TABLE 1
id Name Desig
1 Ali Assistant.Manager
1 Ali Manager
2 John Manager
Now if i want to check status of id 1, it should return Designation(i.e Assistant.Manager & Manager)

Try this:
SELECT T1.Desig
FROM TableName T1 JOIN
(SELECT id,name
FROM TableName
GROUP BY id,name
HAVING COUNT(DISTINCT Desig) > 1) T2
ON T1.id=T2.id AND T1.name=T2.name
Result:
DESIG
Assistant.Manager
Manager
See result in SQL Fiddle.

If id is an identity, as you comment, you can choose the latest row per name like:
select *
from (
select row_number() over (
partition by name
order by id desc) as rn
, *
) as SubQueryAlias
where rn = 1 -- Latest row per name

Related

SQL remove duplicate row depend on certain value

I spend day in hope to figure out how to solve this query.
I have following table
ID Name Pregnancy Gender
1 Raghad Yes Female
1 Raghad No Female
2 Ohoud no Male
What I need is to remove duplicate (in this case 1,1) and to keep one of these rows which has a pregnancy status of yes.
To clarify, I can't use delete since it's a restricted database. I can only retrieve data.
Using an exists clause:
DELETE
FROM yourTable t1
WHERE
pregnancy = 'no' AND
EXISTS (SELECT 1 FROM yourTable t2 WHERE t2.ID = t1.ID AND t2.pregnancy = 'yes');
There are other ways to go about doing this, e.g. using ROW_NUMBER, but as you did not tag your database, I offer the above solution which should work on basically any database.
If you want to just view your data with the "duplicates" removed, then use:
SELECT *
FROM yourTable t1
WHERE
pregnancy = 'yes' OR
NOT EXISTS (SELECT 1 FROM yourTable t2 WHERE t2.ID = t1.ID AND t2.pregnancy = 'yes');
If column Pregnancy have just two values "Yes" and "No", in that case you can use ROW_NUMBER() also to get the results.
;WITH CTE
AS (
SELECT *,ROW_NUMBER() OVER (PARTITION BY id ORDER BY Pregnancy DESC) RN
FROM TABLE_NAME
)
SELECT *
FROM CTE
WHERE RN = 1
In case of multiple values when you want to give highest priorty to "Yes", you can write your query like following
;WITH CTE
AS (
SELECT *,ROW_NUMBER() OVER
(PARTITION BY id ORDER BY CASE WHEN Pregnancy = 'Yes' then 0 else 1 end) RN
FROM TABLE_NAME
)
SELECT *
FROM CTE
WHERE RN= 1
For this sample data you can group by ID, Name, Gender and return the maximum value of the column Pregnancy for each group since Yes is greater compared to No:
SELECT ID, Name, MAX(Pregnancy) Pregnancy, Gender
FROM tablename
GROUP BY ID, Name, Gender
See the demo.
Results:
> ID | Name | Pregnancy | Gender
> -: | :----- | :-------- | :-----
> 1 | Raghad | Yes | Female
> 2 | Ohoud | No | Male
Here is how you could do it in MySQL 8.
Similar Common Table Expressions exist in SQL Server and Oracle.
There you may need to add a comma after then closing parentheses that
ends the CTE (with) definition.
with dups as (
Select id from test
group by id
Having count(1) > 1
)
select * from test
where id in (select id from dups)
and Pregnancy = 'Yes'
union all
select * from test where id not in (select id from dups);
You can see it in action, by running it here
Note this does it without deleting the original.
But it gives you a result set to work with that has what you want.
If you wanted to delete, then you could use this instead, after the dups CTE definition:
delete from test
where id in (select id from dups) and Pregnancy = 'No'
Or distill this into:
delete from test
where id in (Select id from test
group by id
Having count(1) > 1) and Pregnancy = 'No'
1) First of all, update design of your table. ID must be primary key. This would automatically restrict the duplicate rows having same ID.
2) You can use Group by and having clause to remove duplicates
delete from table where pregnancy='no' and exists (SELECT
id
FROM table
GROUP BY id
HAVING count(id)>1)

Remove duplicates in Select query based on one column

I want to select without duplicate ids and keep row '5d' and not '5e' in select statement.
table
id | name
1 | a
2 | b
3 | c
5 | d
5 | e
I tried:
SELECT id, name
FROM table t
INNER JOIN (SELECT DISTINCT id FROM table) t2 ON t.id = t2.id
For the given example an aggregation using min() would work.
SELECT id,
min(name) name
FROM table
GROUP BY id;
You can also use ROW_NUMBER():
SELECT id, name
FROM (
SELECT id, name, ROW_NUMBER() OVER(PARTITION BY id ORDER BY name) rn
FROM mytable
) x
WHERE rn = 1
This will retain the record that has the smallest name (so '5d' will come before '5e'). With this technique, you can also use a sort criteria on another column that the one where duplicates exists (which an aggregate query with MIN() cannot do). Also, queries using window functions usually perform better than the equivalent aggregate query.
If you want to keep the row with the smallest name then you can use not exists:
select t.* from tablename t
where not exists (
select 1 from tablename
where id = t.id and name < t.name
)

need employee details who has only one employment

need employee details who has only one employment
for example this is the table
ID Name StartDate EndDate
1 Fischel 01-May-97 Jan-99
1 Fischel 08-May-92 02-Feb-99
1 Fischel 11-May-92 04-May-10
2 David 10-aug-1980 05-May-1981
3 John 12-sep-1988 06-June-2009
3 John 23-Aug-92 01-Nov-11
Output like this
2 David 10-aug-1980 05-May-1981
Select * from
(select *,row_number() over (partition by id order by StartDate desc ) as rnm
from your table
)Derived_Table
where Derived_Table.rnm=1;
OR
select * from table where id in (
select id
from table group by id having count(*) =1) z;
Use NOT EXISTS to return a user if same user-name doesn't have any other dates.
select ID, Name, StartDate, EndDate
from tablename t1
where not exists (select 1 from tablename t2
where t2.id = t1.id
and (t2.StartDate <> t1.StartDate
or t2.EndDate <> t1.EndDate))
Or, have a sub-query that return all id only appearing once:
select ID, Name, StartDate, EndDate
from tablename t1
where id in (select id from tablename
group by id
having count(*) = 1)

Oracle SQL to delete duplicate records based on columns

I have a table with records:
DATE NAME AGE ADDRESS
01/13/2014 abc 27 us
01/29/2014 abc 27 ma <- duplicate
02/03/2014 abc 27 ny <- duplicate
02/03/2014 def 28 ca
I want to delete the record number 2 and 3 since they are duplicates for record 1 based on name and age. DATE column is a timestamp based from the record when it was added (sql date) and considered unique.
I found this sql but not sure if it will work and a bit concerned as the table has 2 million records and delting the wrong ones will be a bad idea:
SELECT A.DATE, A.NAME, A.AGE
FROM table A
WHERE EXISTS (SELECT B.DATE
FROM table B
WHERE B.NAME = A.NAME
AND B.AGE = A.AGE);
There are many instance of this records so if someone can help me write a sql to delete this records?
Query
DELETE FROM tbl t1
WHERE dt IN
(
SELECT t1.dt
FROM tbl t1
JOIN tbl t2 ON
(
t2.name = t1.name
AND t2.age=t1.age
AND t2.dt > t1.dt
)
);
Fiddle demo
delete from table
where (date, name, age) not in ( select max( date ), name, age from table group by name, age )
Before delete verify with
select * from table
where (date, name, age) not in ( select max( date ), name, age from table group by name, age )
ROW_NUMBER analytical function will helpful (supported by Oracle and Sqlserver).
The logic of assigning a unique ordered number for each row inside a partition, needs to be implemented carefully inside ORDER BY clause.
SELECT A_TABLE.*,
ROW_NUMBER ()
OVER (PARTITION BY NAME, AGE
ORDER BY DATE DESC)
seq_no
FROM A_TABLE;
Then you may use the result for delete operation:
Delete A_TABLE
where DATE,NAME,AGE IN
(
SELECT DATE,NAME,AGE FROM
(
SELECT A_TABLE.*,
ROW_NUMBER ()
OVER (PARTITION BY NAME, AGE
ORDER BY DATE DESC)
seq_no
FROM A_TABLE;
)
WHERE seq_no != 1
)

SELECT TOP from each group

Sorry guys, I'm gettin crazy with this...
My table:
ID Name Surname Capital Capital_Group Job Job_Group
---------- -------- ----------- ------------- ------ --------------
1 Michael Jackson LessThan50 Entertainer
1 Michael Jackson Medium Entertainer
2 John Lennon Small Swimmer
3 Clara Clinton Huge Runner
3 Clara Clinton Huge Sportsmen
I just want to get top row from each ID but not based on anything except that it occurs above the rest (it's already sorted). Any help apreciated, my sanity is at stake.
Presuming that your table sorted by Capital in descending order for each id and that id defines a group, the following may do what you want:
select t.*
from mytable as t
where not exists (select 1
from mytable as t2
where t2.id = t.id and t2.capital > t.capital
);
SELECT t.*
FROM mytable AS t
WHERE t.capital = (SELECT MAX(capital)
FROM mytable t2
WHERE t2.id = t.id)
Incidentally, what do you want to do when there are two people with the same id and capital?
with cte
(
select *, row_Number() over(Partition by ID order by Name ) as RowNumber
)
select * from cte
where RowNumber=1
try this, let me know ur comments on this.
SELECT *
FROM yourTable
GROUP BY id
HAVING MAX(Capital)
select distinct ID ,Name ,Surname,Capital from mytable order by ID
select *,row_number() over(order by ID) as RNO into #temp1
select * from #temp as t where RNO not in (select max(RNO) from #temp as tt group by ID )
i think it will help you