SQL query to delete/identify cross linked data in a table - sql

I've a SQL DB table ABC, in that I've two columns i.e. column1 and column2.
In this table I have some data like.
column1 column2
-------------------
1 2
1 7
2 1
3 4
7 1
4 3
Now, I have to delete the data from this table which are cross linked to each other. for e.g.
(1,2) are cross linked to (2,1)
(1,7) are cross linked to (7,1)
(3,4) are cross linked to (4,3)
So, I need to delete one of value from this pair. My final output should be like:
column1 column2
-------------------
1 2
1 7
3 4
OR
column1 column2
-------------------
2 1
4 3
7 1
I want to write a sql query to do this. Anyone has any idea how can I achieved this?

Try this:
SQLFIDDLE
with pairs as (select
case when c1< c2 then c1 else c2 end as minc,
case when c1< c2 then c2 else c1 end as maxc
from t
group by
case when c1< c2 then c1 else c2 end ,
case when c1< c2 then c2 else c1 end
having count(*) >1)
select *
from t
where not exists
(select * from pairs
where c1= minc and c2= maxc
)
Explain
The CTE table returns all paired rows of one side.
Through NOT EXISTS, it returns all rows not paired
If you change the condition of where c1= minc and c2= maxc to where c2= minc and c1= maxc will get the opposite side of the pairs.
If you want delete one side of those pairs, with DELETE FROM T WHERE EXISTS instead of NOT EXISTS
There have some different ways to get paired rows.

SELECT A.* FROM test A LEFT JOIN test B
ON A.column1 = B.column2 AND A.column2 = B.column
WHERE B.column IS NULL;
This should work, assuming your OK with something like (2,2) also being excluded.

Related

Join Two Column into New Column

How do I combine both COLUMN2 of table1 and table2?
SELECT COLUMN1, COLUMN2 FROM TABLE1
C1 C2
A 1
SELECT COLUMN1, COLUMN2 FROM TABLE2
C1 C2
A 1
B 2
C 2
C1 C2 C3
A 1 1
B 2 0
C 2 0
I want to have a third column combining column2 of both tables base on column1 which has a value of A, B, C. Then if it's null in either table the value should be 0 Please see third sample for sample result.
So you want to match records from both tables on the basis of key column COLUMN1. If a record exists in only one table display that. COLUMN3 indicates whether the key exists in both tables.
This solution uses FULL OUTER JOIN, so it will work whether a record exists in T1 but not T2 or in T2 but not T1. The coalesce() function displays the first non-null argument.
SELECT coalesce(t1.COLUMN1, t2.COLUMN1) as COLUMN1
, coalesce(t1.COLUMN2, t2.COLUMN2) as COLUMN2
, case when t1.COLUMN1 is not null
and t2.COLUMN1 is not null then 1 else 0 end as COLUMN3
FROM TABLE1 t1
full outer join TABLE2 t2
on t1.COLUMN1 = t2.COLUMN1
Assumption. This query ignores the scenario where t1.COLUMN1 = t2.COLUMN1 but t1.COLUMN2 != t2.COLUMN2. It will just show t1.COLUMN2 in the result set. If this is not the outcome you desire please **edit your question ** to include more sample data and the full required output.
To avoid confusion, lets say table_1 has 2 columns(C1,C2) and table_2 has 2 columns(C3,C4). I just renamed column 1 & 2 of table_2 to column 3 & 4.
From What I understood from your question you want all records of table_2 in the result along with a new column which contains values from table_1 based c3 column.
The requires Table_1 right outer join Table_2 with NVL to display 0 against which value is missing in table_1 (B & C)
Full Query is as follows
SELECT Y.COLUMN_3, Y.COLUMN_4, NVL (X.COLUMN_2, 0)
FROM TABLE_1 X RIGHT OUTER JOIN TABLE_2 Y ON (X.COLUMN_1 = Y.COLUMN_3);
Hope this answers your query. Please mark the answer accepted if this solves your problem.
Please try this code...
select dbo.Table_2.C1,
dbo.Table_2.C2,
[C3] = (select Case when dbo.Table_1.C2 = dbo.Table_2.C2 then 1 else 0 end)
from dbo.Table_2
left join dbo.Table_1 on dbo.Table_1.C1 = dbo.Table_2.C1
This is what you must be looking for
SELECT tbl1.C1,
tbl2.C2,
[C3] =
(
SELECT CASE
WHEN tbl1.C2 Is Null OR tbl2.C2 is null
THEN 0
ELSE 1
END
)
FROM tbl1
INNER JOIN tbl2 ON tbl1.C1 = tbl2.C1;
Try This
select table2.c1,
table2.c2,
case when table1.c2 is null or
table2.c2 is null
then 0 else 1 end c3
from table1,table2 where table1.c1(+)=table2.c1;

How to find doubles in master-child table?

I need help with a query to find doubles. Let met explain the situation by example:
tableA (the master table) has a key field keyA with these values :
keyA
1
2
3
etc
tableB (the client table) has a foreign key field keyA and a value field, fieldB
keyA fieldB
1 a
1 b
2 a
2 b
3 a
3 c
4 a
4 b
4 c
etc
So, the values for fieldB in child table tableB are:
for tableA.keyA = 1 are: a and b
for tableA.keyA = 2 are: a and b
for tableA.keyA = 3 are: a and c
for tableA.keyA = 4 are: a, b and c
Now, given a value for keyA I need to find all records in tableA that have matching records in tableB for the field fieldB.
For example, if I search with keyA = 1 then
tableA.keyA = 2 is OK because both have same tableB.fieldB (a and b versus a and b)
tableA.keyA = 3 is not OK because both have not same tableB.fieldB (a and b versus a and c)
tableA.keyA = 4 is not OK because both have not same tableB.fieldB (a and b versus a, b and c)
I need a query that can give me this result. I hope someone can help me with this or can point me into the right direction.
Try this simple query , hope this will solve your problem
DECLARE #vkey int = 1
;WITH cte_test AS (
SELECT keyA,(SELECT ','+fieldb FROM tableB t1 WHERE t1.keyA = t.keyA FOR XML path('')) AS rslt
from tableB t
GROUP BY t.keyA)
SELECT t2.*
FROM cte_test t1
INNER JOIN cte_test t2 ON t1.[rslt] = t2.[rslt] AND t2.[keyA] <> t1.[keyA]
WHERE t1.[keyA] = #vkey
If there is no other item have the same combination , then there is no records in the result, otherwise it will return the matched items.
Assuming there are no duplicates, you can do this with a self-join and aggregation:
select c.keyA, c2.keyA
from (select c.*, count(*) over (partition by keyA) as numBs
from clientTable c
) c join
(select c.*, count(*) over (partition by keyA) as numBs
from clientTable c
) c2
on c2.fieldB = c.fieldB and
c2.keyA <> c.keyA and
c.keyA = 1 -- or whatever key you want to check
where c.numBs = c2.numBs
group by c.keyA, c2.keyA, c.numBs, c2.numBs
having count(*) = c.numBs;
The idea is to count the number of fieldB values for each keyA. These need to be equal (where c.numBs = c2.numBs) and to check that all match (having count(*) = c.numBs).

SQL joining on >=

I have a table like this in ORACLE
a b
-- --
1000 1
100 2
10 3
1 4
My other table has numbers like '67' or '112' in a column called numbers for example.
How can I join to this table using those values and get the correct result where >=1000 would be 1 and >= 100 would be 2 >=10 would be 3 etc.
I tried to do a
select g.b
from table o
join table2 g on o.column >= g.a
when I do this say 1002 was the value of g I would get the back these results.
1
2
3
4
when I just want 1
Easiest would be if your lookup table had ranges instead of just one number, such as row 1 = 1000,9999,1 and row 2 = 100,999,2 etc.
Then your join might be
SELECT OtherTable.n, lookup.b
from OtherTable
LEFT JOIN lookup on OtherTable.n between lookup.low and lookup.high
But, if you really want to use your original table, then on SQL Server, do this:
/*CREATE TABLE #A (a int,b int)
INSERT INTO #A VALUES (1000,1),(100,2),(10,3),(1,4)
CREATE TABLE #B (n INT)
INSERT INTO #B VALUES (67),(112),(4),(2001)
*/
SELECT B.n, A1.b
FROM #B B OUTER APPLY (SELECT TOP 1 a,b FROM #A A WHERE A.a<B.n ORDER BY A.a DESC) A1
Here's one way to do it using a subquery to get the MAX of column a, and then rejoining on the same table to get b:
select t.numericvalue, t2.b
from (
select t.numericvalue, max(t2.a) maxb
from table1 t
join table2 t2 on t.numericvalue >= t2.a
group by numericvalue
) t join table2 t2 on t.maxb = t2.a
SQL Fiddle Demo

SQL Multiple Tables

I have 2 sets of 2 corresponding tables (4 tables total). The two sets only correspond in one column. I want the query to search through that one column in both joined tables, and be able to return the value in the selected column, even if that column doesn't exist in the other table.
Currently, my query looks like:
select z
FROM A1
INNER JOIN A2
ON A1.x=A2.x
WHERE A1.x= '25'
UNION
select z
FROM B1
INNER JOIN B2
ON B1.x=B2.x
WHERE B1.x= '25'
UNION works as long as I am looking for a column which both (joined) tables A and B have in common. I'd like to be able to get values from columns which only exist in A or in B, but not necessarily both of them.
Thanks in advance.
Edit:
Basically, I want two completely separate queries on separate tables, but in one query, with only one select.
Example:
Table A1
x | y
------
1 | a
2 | b
Table A2
x | z
------
1 | c
2 | d
Table B1
x | v
------
3 | e
4 | f
Table B2
x | w
------
3 | g
4 | h
So I want look for a column variable (such as v,w,y, or z), with a specified value of x. e.g. select w where x=4 should give me h; select z where x=2 should give me d.
You must have the same number of columns in each select statement when using UNION. You can add constant values for columns that are missing. You must also have the same data type for each column.
select Column1, null as Column2
from T1
union
select '', Column2
from T2
As per comment by #Adrian, you can of course use null as a constant value. Otherwise you need to pick a constant value of the data type that is used for the column.
select Column1, null as Column2
from T1
union
select null, Column2
from T2
Use the sample data provided in the question:
select A1.x, A2.z as 'y'
from A1
inner join A2
on A1.x=A2.x
where A1.x= 4
union
select B1.x, B2.w as 'y'
from B1
inner join B2
on B1.x=B2.x
where B1.x= 4
Result:
x y
4 h
With a 2 instead of a 4
Result:
x y
2 d
It would be something like that:
select Column1, ColumnThatOnlyExistsInContextA, null as ColumnThatOnlyExistsInContextB
FROM A1
INNER JOIN A2
ON A1.ID=A2.ID
WHERE A1.ID= '25'
UNION
select Column1, null, ColumnThatOnlyExistsInContextB
FROM B1
INNER JOIN B2
ON B1.ID=B2.ID
WHERE B1.ID= '25'
When using UNION, make sure all queries return result sets that have the same number of columns with the same type. If you want to return a column from the second query in a union that the first query doesn't have, you can modify your first query to have a NULL value for that column.
So you basically want to do:
select Column1
FROM A1
INNER JOIN A2
ON A1.ID=A2.ID
WHERE A1.ID= '25'
UNION
select Column2
FROM B1
INNER JOIN B2
ON B1.ID=B2.ID
WHERE B1.ID= '25'
right?
If so, your problem is probably just that Column1 and Column2 are different types. So, do something like
select cast(Column1 as varchar(255))
and
select cast(Column2 as varchar(255))
Should work!
Well, UNION's only requirement is that the number and type of the fields in each result set being UNIONed must match. So, if B has a Column2 and A doesn't, you can select Column1 from the joined As and Column2 from the joined Bs, and provided A.Column1 and B.Column2 are the same type (you can CAST or CONVERT if necessary) the statement will still work. Maybe I'm not understanding the problem, but I think it's pretty easy to solve.

SQL Getting Data with extra row

I have two tables with columns of my interests as Table1.Column1 and Table2.Column2
Table1 is Kind of a Group Table and Table2 is items table. The join query of these two tables gets the data in the followinf format
Column1 Column2
A 1
A 2
B 1
B 2
B 3
What I want is to get data in the following format:
Column1 Column2
A 0
A 1
A 2
B 0
B 1
B 2
B 3
i.e. getting extra 0 for each group at the start each time. The 0 does not exits in the database.
Does anyone know how to achive this in SQL?
Many Thanks,
This is one way to do it.
SELECT DISTINCT Column1, [Column2] = 0
FROM (
YourOriginalQuery
) q
UNION ALL
YourOriginalQuery
Most likely, there are better solutions by incorporating this requirement into your original query. If you post your query, we can come up with better alternatives.
Or something like:
select C.CategoryId, drv.CategoryGroupId from Category as C
cross join (
select 0 as CategoryGroupId
UNION
select CG.CategoryGroupId from CategoryGroup as CG
)drv order by CategoryId, CategoryGroupId