Delete reverse duplicate rows using sql - sql

column1 column2
x y
y x
how does one go about eliminating such duplicates? or at worst selecting just one of those tuples?

It's become kind of a mainstream habit among question askers to withhold the information which RDBMS we are dealing with. In response: this is tested and works with a certain RDBMS I am not inclined to name. Go figure!
DELETE FROM tbl a
USING tbl b
WHERE (a.x, a.y) = (b.y, b.x)
AND a.y > a.x -- keep the one dupe with the biggest x
Assuming there are no dupes with x = y. This would be an ordinary duplicate anyway.

One approach is to identify only the valid rows e.g.
SELECT column1, column2
FROM T
WHERE column1 <= column2
UNION
SELECT column2 AS column1, column1 AS column2
FROM T
WHERE column1 > column2;
...then delete rows that aren't in the set of valid rows:
DELETE
FROM T
WHERE NOT EXISTS (
SELECT *
FROM (
SELECT column1, column2
FROM T
WHERE column1 <= column2
UNION
SELECT column2 AS column1, column1 AS column2
FROM T
WHERE column1 > column2
) AS DT1
WHERE DT1.column1 = T.column1
AND DT1.column2 = T.column2
);
Alternatively, the DELETE may be simplified to target only the invalid rows:
DELETE
FROM T
WHERE column1 > column2
AND EXISTS (
SELECT *
FROM T AS T1
WHERE T1.column1 = T.column2
AND T1.column2 = T.column1
);

Related

Removing Partitioned rows from oracle sql query output

I have below query
SELECT ROW_NUMBER() OVER ( PARTITION BY COLUMN1, COLUMN2, COLUMN3 ORDER BY COLUMN1, COLUMN2) AS ROW_NUM, COLUMN1, COLUMN2, COLUMN3
FROM (SUBQUERY)
GROUP BY COLUMN1, COLUMN2, COLUMN3
OUTPUT of above query:-
I need to perform something equivalent to
IF (COLUMN2 == 'PQR' AND COLUMN3 IS NOT NULL)
THEN
"Delete whole partition from output having value A3 in column1"
Explaination:-
If COLUMN2 is having value PQR and COLUMN3 is having any DATE_TIME (i.e. NOT NULL) then all the corresponding COLUMN1 value should not be present in output of query.
OUTPUT required is:-
I tried to be as clear as I can be. Let me know if I need to clarify my question more.
NOTE:- I want to remove those rows only from output of the query not from actual table.
If you are doing this using a subquery, then you might want to use window functions:
SELECT s.*
FROM (SELECT ROW_NUMBER() OVER ( PARTITION BY COLUMN1, COLUMN2, COLUMN3 ORDER BY COLUMN1, COLUMN2) AS ROW_NUM,
COLUMN1, COLUMN2, COLUMN3,
COUNT(CASE WHEN COLUMN2 = 'PQR' THEN COLUMN3 END) OVER (PARTITION BY COLUMN1) as cnt
FROM (SUBQUERY)
GROUP BY COLUMN1, COLUMN2, COLUMN3
) s
WHERE cnt = 0;
This counts the number of COLUMN3 values where COLUMN2 = 'PQR' over all each COLUMN1. It then returns only the rows where this count is 0.
The advantage of this approach is that it only evaluates the subquery once -- that can be a performance win (over NOT EXISTS) if it is complicated.
If you want a select query then you can use NOT EXISTS:
SELECT * FROM YOUR_TABLE T1
WHERE NOT EXISTS (SELECT 1 FROM YOUR_TABLE T2
WHERE T1.COLUMN1 = T2.COLUMN1
AND T2.COLUMN2 = 'PQR' AND T2.COLUMN3 IS NOT NULL);
You can use the EXISTS to delete such records as follows:
DELETE FROM YOUR_TABLE T1
WHERE EXISTS (SELECT 1 FROM YOUR_TABLE T2
WHERE T1.COLUMN1 = T2.COLUMN1
AND T2.COLUMN2 = 'PQR' AND T2.COLUMN3 IS NOT NULL);

How to combine multiple columns into one column?

I'm writing a query and want the results in one column
My current results return like this
Column1 Column2 column3
1 A CAT
I want the results to return like this
Column1
1
A
CAT
SELECT Column1 FROM TableName
UNION ALL
SELECT Column2 FROM TableName
UNION ALL
SELECT Column3 FROM TableName
If you don't want duplicate values, use UNION instead of UNION ALL.
You can also do this using UNPIVOT operator
SELECT Column123
FROM
(
SELECT Column1, Column2, Column3
FROM TableName
) AS tmp
UNPIVOT
(
Column123 FOR ColumnAll IN (Column1, Column2, Column3)
) AS unpvt;
https://www.w3schools.com/sql/sql_union.asp
https://www.mssqltips.com/sqlservertip/3000/use-sql-servers-unpivot-operator-to-help-normalize-output/
The answer is.. it depends..
If the number of columns are unknown.. then use unpivot as UZI has suggested
if you know all columns and is a small finite set..
you can simply go
Select
column1
from table
union all
select column2
from table
union all
select column3
from table
The Cartesian product of the T table with derived table of 3 rows.(each row of #t is presented 3 times, for а=1 and а=2 and а=3). For the first case we take value from Column1,
and for the second - from Column2 and for the Third - from Column3.
Here, certainly, there is both union and join but, in my opinion, the title's question means single scanning the table.
CREATE TABLE #t (Column1 NVARCHAR(25),Column2 NVARCHAR(25), column3 NVARCHAR(25))
INSERT INTO #t
SELECT '1','A','CAT'
SELECT
CASE a WHEN 1 THEN Column1 WHEN 2 THEN Column2 ELSE column3 END col
FROM #t, (SELECT 1 a UNION ALL SELECT 2 UNION ALL SELECT 3) B
DROP TABLE #t

Changing column in set update

Can I use a case statement in Set Column? I have multiple columns that need to be updated but the statement is quite similar. The only difference is what I'm selecting.
UPDATE TABLE1 A
SET A.COLUMN2 = (SELECT....
I want to update column2 to Column1 without repeating the same block of code.
Note: I'm using LISTAGG
Is there any way I could distinct both of the columns without trying to separate it in one query the make a subquery
I'm using this query and I know that listagg don't have the capabilities to distinct unless you distinct it first before using listagg
SELECT LISTAGG(COLUMN1 , ', ') WITHIN GROUP (ORDER BY COLUMN1) AS COLUMN1 ,
LISTAGG(COLUMN2 , ', ') WITHIN GROUP (ORDER BY COLUMN2) AS COLUMN1
FROM (SELECT COLUMN1 , COLUMN2 FROM TABLE2 B
WHERE A.COLUMN3 = B.COLUMN3
GROUP BY COLUMN1 , COLUMN2);
COLUMN1 COLUMN2
EGG PIE
EGG BREAD
Expected output
COLUMN1 COLUMN2
EGG PIE; BREAD
Do you mean
UPDATE table1
SET (column1, column2 ...) = (SELECT col1, col2 ...)

Select statement for Oracle SQL

I have a table say,
column1 column2
a apple
a ball
a boy
b apple
b eagle
b orange
c bat
c ball
c cork
Now I would like to fetch column1 based on the rows that doesn't contain 'apple' and also ignore values in column1 if any of the rows have 'apple' in it. So in the table above only 'C' must be retured.
I am kind of new to Oracle SQL and I know Select column1 from table where column2 != 'apple' will not work. I need some help with this please.
You could use DISTINCT with NOT IN in following:
QUERY 1 using NOT IN
select distinct col1
from t
where col1 not in (select col1 from t where col2 = 'Apple')
QUERY 2 using NOT EXISTS
As per #jarlh comment you could use NOT EXISTS in following:
select distinct col1
from #t t1
where not exists (select 1 from #t t2 where col2 = 'Apple' and t1.col1 = t2.col1)
SAMPLE DATA
create table t
(
col1 nvarchar(60),
col2 nvarchar(60)
)
insert into t values
('a','apple')
,('a','ball')
,('a','boy')
,('b','apple')
,('b','eagle')
,('b','orange')
,('c','bat')
,('c','ball')
,('c','cork')
Assuming that column1 is NOT NULL you could use:
SELECT DISTINCT t.column1
FROM table_name t
WHERE t.column1 NOT IN (SELECT column1
FROM table_name
WHERE column2 = 'apple');
LiveDemo
To get all columns and rows change DISTINCT t.column1 to *.
Select * from tbl
Left join (
Select column1 from tbl
Where column2 like '%apple%'
Group by column1
) g on tbl.colum1 = g.column1
Where g.column1 is null
Seems to me that you need to find a summary of all colum1 values that have any reference to apple. Then list the rows that have no match to the summary list (g)
If I understand well, you need the values af column1 such that in your table does not exist a row with the same value of column1 and 'apple' in column2; you can translate this in SQL with:
Select column1
from your_table t
where not exists (
select 1
from your_table t2
where t2.column1 = t1.column1
and t2.column2= 'apple'
)
This is only one of the possible ways to get your result, soyou can rewrite it in many ways; I believe this way of writing is similar enough to the logics to clearly explain how a logic could be written in plain SQL.

if else in where clause on Oracle

I need a query but I have a criteria depends on situation. As an example :
Lets have a table named table1 that has column named column1 and
table2 that has column named column2
In the query in where clause, I need to join this table1 with table2 by column1 and column2 columns. But, I need to do like
if
column1 = 'x' then my criteria must be column1 = column2
else
column1 != 'x'
How I can write this where clause in Oracle?
Thank you for your answer.
Try this
WHERE (Column1 != 'x' OR (Column1 = 'x' AND column1 = column2))
Just use OR condition like this one:
WHERE (Column1 <> 'x' OR column1 = column2)
(This is normal SQL syntax. Don't know if there is any change in syntax of Oracle. But you can try this logic)
EDIT: (From OP's comment in my answer)
You can do that something like this one:
WHERE (column2 != (Select col from table3) OR column1 = 'x')
Or
WHERE (column2 != (Select col from table3) OR column1 = (Select col from table3))