How to find unique pairs from two columns in SQL? - mysql

i have a table"Dummy" with columns "col1 and col2".
How do i find unique pairs from(col1,col2). For example in the above table how do i get (a,b) or (b,a) only as my output, instead of both (a,b) and (b,a).
select
distinct
col1
col2
from
dummy
where
dummy.col1 < dummy.col2
group by
col1,
col2;
the above query is wrong as it missed out the pair (d,c).

i would rather use concat and group by
SELECT
col1,col2
FROM
tbl
GROUP BY CONCAT(LEAST(col1, col2),
GREATEST(col1, col2))
OR SIMPLY
SELECT
col1,col2
FROM
tbl
group by LEAST(col1, col2),GREATEST(col1, col2)

If you don't care if an existing combination is returned in the right order, e.g. a,b might also be returned asb,a:
SELECT DISTINCT
CASE WHEN col1 > col2 THEN col2 ELSE col1 end, -- similar to LEAST
CASE WHEN col1 < col2 THEN col2 ELSE col1 end -- similar to GREATEST
FROM dummy
;
But if you must return an existing row it' more complicated:
SELECT t1.*
FROM dummy AS t1 LEFT JOIN dummy AS t2
ON t1.col1 = t2.col2
AND t1.col2 = t2.col1
AND t1.col1 > t2.col1
WHERE t2.col1 IS NULL
;
SELECT col1,col2
FROM dummy AS t1
WHERE NOT EXISTS(
SELECT * FROM dummy t2
WHERE t1.col1 = t2.col2
AND t1.col2 = t2.col1
AND t1.col1 > t2.col1
);

SELECT
x,
y
FROM
(
SELECT
DISTINCT
col1 AS x,
col2 AS y
FROM
dummy
WHERE
col1 <> col2
UNION
SELECT
DISTINCT
col1 AS y,
col2 AS x
FROM
dummy
WHERE
col1 <> col2
)

Use least and greatest.
select least(col1,col2),greatest(col1,col2)
from tbl
group by least(col1,col2),greatest(col1,col2)
But this may return rows that aren't in the table if only one pair of (x,y) or (y,x) exists.
To avoid that, use
select least(col1,col2) as col1,greatest(col1,col2) as col2
from tbl
group by least(col1,col2),greatest(col1,col2)
having count(*)>1
union all
select col1,col2
from tbl
where (least(col1,col2),greatest(col1,col2)) in (select least(col1,col2) as col1,greatest(col1,col2) as col2
from tbl
group by least(col1,col2),greatest(col1,col2)
having count(*)=1
)

Related

Select query in IF statement MYSQL

In my MySql database, I want to create select query which should give output like this:
in my select query i want a column output as 1, if the column value present in a list returned by a select query else 0 .
Select col1,col2,
,IF col3 IN
((select col from tabl2 ),1,0)AS col5
from tbl1.
Thanks in Advance
SELECT col1, col2,
IF col3 IN ((select col from tabl2 ),1,0) AS col5
FROM tbl1
Using IF and subquery in MySQL
SELECT table1.column1, table1.column2,
(
SELECT IF (
(SELECT column3 FROM table1 WHERE column3 IN (SELECT column FROM table2)), 1, 0
)
) AS column_output
FROM table1
In general:
SELECT col1,
col2,
CASE WHEN col3 IN (select col from tabl2)
THEN 1
ELSE 0
END AS col5
FROM tbl1
Specific for MySQL:
SELECT col1,
col2,
col3 IN (select col from tabl2) AS col5
FROM tbl1

How to get a similar value in Oracle

I have a table of two columns
Col1 Col2
A 1
A 2
A 3
B 1
B 2
B 3
Output I need is like this
Col1 Col2
A 1
A 1,2
A 1,2,3
B 1
B 1,2
B 1,2,3
Thank you in advance.
Here is a solution which would work for MySQL. It uses a correlated subquery in the select clause to group concatenate together Col2 values. The logic is that we only aggregate values which are less than or equal to the current row, for a given group of records sharing the same Col1 value.
SELECT
Col1,
(SELECT GROUP_CONCAT(t2.Col2 ORDER BY t2.Col2) FROM yourTable t2
WHERE t2.Col2 <= t1.Col2 AND t1.Col1 = t2.Col1) Col2
FROM yourTable t1
ORDER BY
t1.Col1,
t1.Col2;
Demo
Here is the same query in Oracle:
SELECT
Col1,
(SELECT LISTAGG(t2.Col2, ',') WITHIN GROUP (ORDER BY t2.Col2) FROM yourTable t2
WHERE t2.Col2 <= t1.Col2 AND t1.Col1 = t2.Col1) Col2
FROM yourTable t1
ORDER BY
t1.Col1,
t1.Col2;
Demo
Note that the only real change is substituting LISTAGG for GROUP_CONCAT.
with s (Col1, Col2) as (
select 'A', 1 from dual union all
select 'A', 2 from dual union all
select 'A', 3 from dual union all
select 'B', 1 from dual union all
select 'B', 2 from dual union all
select 'B', 3 from dual)
select col1, ltrim(sys_connect_by_path(col2, ','), ',') path
from s
start with col2 = 1
connect by prior col2 = col2 - 1 and prior col1 = col1;
C PATH
- ----------
A 1
A 1,2
A 1,2,3
B 1
B 1,2
B 1,2,3
6 rows selected.

Getting duplicate rows by several columns in MySQL

I'm trying to search duplicate rows by several columns in large table (near 18 000 rows). Problem is that queries take a lot of time, I tried this:
SELECT * FROM table_name a, table_name b
WHERE a.col1 = b.col1
AND a.col2 = b.col2
AND a.col3 = b.col3
AND a.col4 = b.col4
AND a.id <> b.id
and this:
SELECT *
FROM table_name
WHERE col1 IN (
SELECT col1
FROM table_name
GROUP BY col1
HAVING count(col1) > 1
)
AND col2 IN (
SELECT col2
FROM table_name
GROUP BY col2
HAVING count(col2) > 1
)
AND col3 IN (
SELECT col3
FROM table_name
GROUP BY col3
HAVING count(col3) > 1
)
AND col4 IN (
SELECT col4
FROM table_name
GROUP BY col4
HAVING count(col4) > 1
)
they both work, but too slow. Any ideas?
You can try using one joint GROUP BY statement like:
SELECT * FROM table_name
GROUP BY col1, col2, col3, col4
HAVING count(*) > 1
At the very least, it will look cleaner.
EDIT
To return all results as a sub-set for the previous column:
SELECT *
FROM table_name
WHERE col4 IN (
SELECT col4
FROM table_name
WHERE col3 IN (
SELECT col3
FROM table_name
WHERE col2 IN (
SELECT col2
FROM table_name
WHERE col1 IN (
SELECT col1
FROM table_name
GROUP BY col1
HAVING count(col1) > 1
)
)
)
This, in concept, should give you all results in a faster execution time.

How to show MIN value with whole table

I have table like:
id col1 col2
1 a 55
2 b 77
In result i want to see:
id col1 col2 MIN(col2)
1 a 55 55
2 b 77
Something like that, or in other case, how i can get one minimum value with whole table.
You can use a CROSS JOIN with a subquery which will select the min(col2) value for the entire table:
select t1.id,
t1.col1,
t1.col2,
t2.minCol2
from yourtable t1
cross join
(
select min(col2) minCol2
from yourtable
) t2
See SQL Fiddle with Demo.
If you want to expand this to only show the min(col2) value on the first row, then you could use user-defined variables:
select id,
col1,
col2,
case when rn = 1 then mincol2 else '' end mincol2
from
(
select t1.id,
t1.col1,
t1.col2,
t2.minCol2,
#row:=case when #prev:=t1.id then #row else 0 end +1 rn,
#prev:=t1.id
from yourtable t1
cross join
(
select min(col2) minCol2
from yourtable
) t2
cross join (select #row:=0, #prev:=null) r
order by t1.id
) d
order by id
See SQL Fiddle with Demo
If you had more than one column that you want to compare, then you could unpivot the data using a UNION ALL query and then select the min value for the result:
select t1.id,
t1.col1,
t1.col2,
t2.MinCol
from yourtable t1
cross join
(
select min(col) MinCol
from
(
select col2 col
from yourtable
union all
select col3
from yourtable
) src
) t2
See SQL Fiddle with Demo
You can't. The number of columns is fixed, so you can get the minimum value on all the rows as described by #bluefeet.
You could get it on a smaller number of rows (typically 1) by using the logic:
(case when t2.minCol2 = t1.col2 then t2.minCol2 end)
But this would put NULLs on the other rows.

calculate frequency using sql

I have a table in MySQL:
Col1 | Col2
a A
a B
c C
a B
i want to create a table like this:
col1 | col2 | freq
a A 0.33
a B 0.67
col1 is a specified item in Col1. col2 is distinct item that has occured with the specified item(i.e. a). freq column is the frequency of appearence of item in col2.
Can someone give me a hint of how to create such a query? Thanks a lot.
try this:
Select A.Col1, A.Col2, A.Count1 * 1.0 / B.Count2 As Freq
From (
Select Col1, Col2, Count(*) As Count1
From YourTableName
Group By Col1, Col2
) As A
Inner Join (
Select Col1, Count(*) As Count2
From YourTableName
Group By Col1
) As B
On A.Col1 = B.Col1
You can also use this which is coded in SQL server
DECLARE #Count INT;
SELECT #Count = COUNT(1) FROM YourTableName WHERE Col1 = 'a'
SELECT Col1, Col2, CAST(COUNT(1)* 1.00 /#Count AS DECIMAL(4,2) ) AS Frequency
FROM YourTableName
WHERE Col1 = 'a'
GROUP BY Col1, Col2
this way you have a better performance
With window functions
SELECT Col1, Col2, Count1*1.0 / Count2 AS freq
FROM (
SELECT
Col1,
Col2,
COUNT() OVER(PARTITION BY Col1, Col2) AS Count1,
COUNT() OVER(PARTITION BY Col1) AS Count2
FROM YourTableName
)
GROUP BY Col1, Col2