Delete Rows based on two columns - sql

How can I delete rows based on just two column conditions.
Example
Table 1
id name phone
1 aa 123
1 aa 345
1 bb 123
2 aa 456
1 NULL 123
1 123
My Expected output
id name phone
1 bb 123
2 aa 456
My condition to delete: if id and name is same, delete the rows
If one of the value in a condition is null or blank it should also delete the row as given in the input.

Delete from table1 t where exists (
Select * from
(Select id, name from table1 group by id, name having count(*) > 1) t2 where t.id = t2.id and t.name = t2.name)

This should do what you want. You can do the select first for testing purposes, then remove the Select and uncomment out the delete.
-- This joins on the table the set of data that has more then 1 row with duplicate IDs, and names. Then you can delete from here.
--DELETE t1
SELECT *
FROM Table1 T1
INNER JOIN (
-- this gets all the records that have more then 1 ID and Name that are the same.
SELECT ID, name
FROM Table1
GROUP BY ID, name
HAVING COUNT(*) > 1
) ToDelete ON T1.ID = ToDelete.ID
AND T1.name = ToDelete.name

create table #tablea (
id int,
name varchar(3),
phone int
)
insert into #tablea (id, name, phone)
values
(1,'aa','123'),
(1,'aa','345'),
(1,'bb','123'),
(2,'aa','456')
select * from #tablea
delete a
from #tablea a
inner join (
select id, name
from #tablea
group by id, name
having COUNT(*) > 1
) b on a.id = b.id and a.name = b.name
select * from #tablea
drop table #tablea

Related

Find number of non-unique column values within a group where a second column value is all the same

I have two tables.
Table 1:
id_a,
id_b,
id_t
Table 2:
id_t,
name
If Table 2 name starts with a, I need to find out of anything
with matching id_ts also have matching id_as.
If Table 2 name starts with b, I need to find out of any row
with matching id_ts also have matching id_bs.
I need to know how many times these matches occur.
Table 1
id_a
id_b
id_t
1
0
123
1
0
123
2
0
123
0
4
456
0
4
456
0
5
456
0
5
456
0
5
456
0
6
456
0
7
456
Table 2
id_t
name
123
aaq
456
bws
So in this example, I want to see a result like
id_t
name
num_non_unique
123
aaq
1
456
bws
2
My current code is this:
SELECT
t2.id_t, t2.name, count(t1.*) AS num_non_unique
FROM
Table 2 AS t2
JOIN Table 1 as t1 ON t2.id_t = t1.id_t
WHERE
(t2.name like 'a%' and t1.id_a in (SELECT id_a FROM t1 GROUP BY id_a, id_t HAVING count(*) > 1))
OR (t2.name like 'b%' AND t1.id_b IN (SELECT id_b FROM t1 GROUP BY id_b, id_t HAVING count(*) > 1))
GROUP BY t1.name, t1.id_t
This doesn't currently give me the results I want.
With this code I seem to get the count of all available rows for id_b, and 1 + non_uniques for id_a (so with one non-unique, the value is 2, otherwise the column has a 1).
Any help is appreciated!
Schema and insert statements:
create table table_1(id_a int, id_b int, id_t int);
insert into table_1 values(1, 0, 123);
insert into table_1 values(1, 0, 123);
insert into table_1 values(2, 0, 123);
insert into table_1 values(0, 4, 456);
insert into table_1 values(0, 4, 456);
insert into table_1 values(0, 5, 456);
insert into table_1 values(0, 5, 456);
insert into table_1 values(0, 5, 456);
insert into table_1 values(0, 6, 456);
insert into table_1 values(0, 7, 456);
create table table_2 (id_t int, name varchar(50));
insert into table_2 values(123, 'aaq');
insert into table_2 values(456, 'bws');
Query:
with case1 as
(
select id_t, id_a
from table_1
group by id_t, id_a
having count(*)=1
),
case2 as
(
select id_t,id_b
from table_1
group by id_t,id_b
having count(*)=1
)
select id_t,name,
(case when t2.name like 'a%' then (select count(*) from case1 where case1.id_t=t2.id_t) when t2.name like 'b%' then (select count(*) from case2 where case2.id_t=t2.id_t) end)num_non_unique
from table_2 as t2
Output:
id_t
name
num_non_unique
123
aaq
1
456
bws
2
db<fiddle here
If I understand correctly, you want the count -- for each row in table_2 -- of the corresponding rows in table_1 where id_b only appears once.
One method is:
select t2.*, coalesce(cnt, 0)
from table_2 t2 left join
(select id_a, count(*) as cnt
from (select id_a, id_b
from table_1
group by id_a, id_b
having count(*) = 1
) t1
group by id_a
) t1
on t1.id_a = t2.id_a;
Try this Code:
select name,id_ts,sum(count_) "num_non_unique" from
(
select t1.id_a,t1.id_b,t1.id_ts,t2.name, count(*) "count_"
from tab1 t1
inner join tab2 t2 on t1.id_ts=t2.id_t
group by 1,2,3,4
having count(*)=1
)tab
group by 1,2
Explanation:
As you have mentioned in your question that one column value will always be same based of name starting character. So no need to check the starting of the name in your query.
Simply we will check the count of unique row and filter it by using condition having count(*)=1.
After getting the unique row simply group it to get the count of rows group by name and id_ts
DEMO

Case when duplicate add one more letter

For example: I have a table with these records below
1 A
2 A
3 B
4 C
...
and I need to migrate these record in to another table
1 AA
2 AB
3 B
4 C
...
Meaning if the record is duplicate, it will automatically add one more letter alphabetically.
Just a slightly different approach
Example
Declare #YourTable Table (ID int,[SomeCol] varchar(50))
Insert Into #YourTable Values
(1,'A')
,(2,'A')
,(3,'B')
,(4,'C')
Select *
,NewVal = concat(SomeCol,IIF(sum(1) over (partition by SomeCol)=1,'',char(64+row_number() over ( partition by SomeCol order by ID ))) )
From #YourTable
Returns
ID SomeCol NewVal
1 A AA
2 A AB
3 B B
4 C C
EDIT - Requested UPDATE
Declare #YourTable Table (ID int,[SomeCol] varchar(50))
Insert Into #YourTable Values
(1,'A')
,(2,'A')
,(3,'B')
,(4,'C')
Select *
,NewVal = concat(SomeCol,IIF(sum(1) over (partition by SomeCol)=1,'',replace(char(63+row_number() over ( partition by SomeCol order by ID )),'#','')) )
From #YourTable
Returns
ID SomeCol NewVal
1 A A
2 A AA
3 B B
4 C C
We might be able to handle this requirement with the help of a calendar table mapping secondary letters to duplicate sequence counts:
WITH letters AS (
SELECT 1 AS seq, 'A' AS let UNION ALL
SELECT 2, 'B' UNION ALL
SELECT 3, 'C' UNION ALL
...
SELECT 26, 'Z' UNION ALL
...
),
cte AS (
SELECT id, let, ROW_NUMBER() OVER (PARTITION BY let ORDER BY id) rn,
COUNT(*) OVER (PARTITION BY let) cnt
FROM yourTable
)
SELECT t1.id, t1.let + CASE WHEN t1.cnt > 1 THEN t2.let ELSE '' END AS let
FROM cte t1
LEFT JOIN letters t2
ON t1.id = t2.seq
ORDER BY t1.id;
Demo

multiple select in sql server

I want to search between 2 tables but that field i want to search is foreign key in other table
my tables are like this:
table 1
ID TitleSR
1 888
2 999
table 2
ID TitleSR
1 11
2 22
3 33
4 44
table contain value
ID value
11 italy
22 swiss
888 lilium
999 mount
33 england
I think I understand you. Try this one:
Select *
From table3 as VCT Inner Join
(Select * From table1
Union
Select * From table2) as FGT
On VCT.ID = FGT.TitleSR
Where value = 'italy';
You can use either of these methods:
Returns only t1 fields
SELECT * FROM Table1 t1
WHERE t1.ID in (SELECT ID FROM Table2);
Returns ALL fields
SELECT * FROM Table1 t1
JOIN Table2 t2 on t1.ID = t2.ID;
If your 'values' exist in a separate table (tblValues), you can use any of these:
Returns tblValues fields
SELECT * FROM tblValues tval
WHERE tval.ID in (SELECT TitleSR FROM Table1);
returns ALL fields
SELECT *
FROM (tblValues tval
JOIN Table1 t1 on tval.ID = t1.TitleSR)
JOIN Table2 on tval.ID = Table2.TitleSR;

Get groups that are exactly equal to a table

I have a query that groups easily. I need to get the groups that have exactly the same records to another table (relationship).
I'm using ANSI-SQL under SQL Server, but I accept an answer of any implementation.
For example:
Table1:
Id | Value
---+------
1 | 1
1 | 2
1 | 3
2 | 4
3 | 2
4 | 3
Table2:
Value | ...
------+------
1 | ...
2 | ...
3 | ...
In my example, the result is:
Id |
---+
1 |
How imagined that it could be the code:
SELECT Table1.Id
FROM Table1
GROUP BY Table1.Id
HAVING ...? -- The group that has exactly the same elements of Table2
Thanks in advance!
You can try the following:
select t1.Id
from Table2 t2
join Table1 t1 on t1.value = t2.value
group by t1.Id
having count(distinct t1.value) = (select count(*) from Table2)
SQLFiddle
To get the same sets use an inner join:
SELECT Table1.Id
FROM Table1
INNER JOIN table2 ON table1.id=table2.id
GROUP BY Table1.Id
HAVING ...? --
CREATE TABLE #T1 (ID INT , [Values] INT) INSERT INTO #T1 VALUES (1,1),(1,2),(1,3),(2,4),(2,5),(3,6)
CREATE TABLE #T2 ([Values] INT) INSERT INTO #T2 VALUES (1),(2),(3),(4)
SELECT * FROM #T1
SELECT * FROM #T2
SELECT A.ID
FROM
( SELECT ID , COUNT(DISTINCT [Values]) AS Count FROM #T1
GROUP BY ID
) A
JOIN
(
SELECT T1.ID, COUNT(DISTINCT T2.[Values]) Count
FROM #T1 T1
JOIN #t2 T2
ON T1.[Values] = T2.[Values]
GROUP BY T1.ID
) B
ON A.ID = B.ID AND A.Count = B.Count

Display records linked with two IDs

I have a table
ID NAME
--------
1 AAA
2 BBB
2 AAA
2 CCC
1 DDD
2 DDD
I have to display records which are linked with both ID 1 and 2
NAME
----
AAA
DDD
I am using below query -
Select Name from table1 where ID IN (1,2);
But it is displaying me -
NAME
-----
AAA
BBB
CCC
DDD
How do I change my query to solve this problem?
SELECT DISTINCT NAME
FROM tabel1 t1
join table1 t2
on t1.id = 1 and t2.id = 2 and t1.name = t2.name
or if there can be many matches
SELECT DISTINCT NAME
FROM tabel1 t1
WHERE EXISTS (SELECT 1 FROM table1 t2 WHERE t1.name = t2.name and t2.id = 2)
and t1.id = 1
or
SELECT NAME FROM tabel1 WHERE id = 1
INTERSECT
SELECT NAME FROM tabel1 WHERE id = 2
You need to group by the name, then count the distinct IDs that you wish to filter by.
select name
from table
where id in (1,2)
group by name
having count (distinct ID) = 2
Select Name
from table1
where ID IN (1,2)
and Name in ( select Name
from table1
where ID IN (1,2)
group by Name
having count(id) =2
) ;
Select Name from TableName
where id in (1,2)
group by Name having Count(Distinct Id)>1
select name
from table t
where id = 1 and exists
(select 1 from table where name = t.name and id = 2)