Select only rows that have unique fields - sql

What is an SQL command that checks for rows that have rows with no duplicate fields in them.
ex:
A A A B B B should not be in the resulting table.
Only rows such as A B C D E F
i.e. given data like:
A A A B B B
A B C D E F
A A B G H Q
Should return A B C D E F

There is no simple command to do this.
is seems an unusual requirement and possibly an indication that the table is not in first normal form if all columns are interchangeable.
The following works in Microsoft SQL Server
;With YourData AS
(
select 'A' as C1, 'A' as C2, 'A' as C3, 'B' as C4, 'B' as C5, 'B' as C6 UNION ALL
select 'A' as C1, 'B' as C2, 'C' as C3, 'D' as C4, 'E' as C5, 'F' as C6
)
SELECT *
FROM YourData
WHERE 1 =
( SELECT TOP 1 COUNT(*) AS Cnt
FROM (
SELECT C1 AS C
UNION ALL
SELECT C2
UNION ALL
SELECT C3
UNION ALL
SELECT C4
UNION ALL
SELECT C5
UNION ALL
SELECT C6
) D
GROUP BY C
ORDER BY Cnt DESC
)

Select distinc * returns unique ROWS not unique values from fields.
You should compare each column's value with others. (Assuming column types are the same). For example, for a 4 column table you should do smoething like:
SELECT Col1, Col2, Col3, Col4 FROM MyTable WHERE
Col1 NOT IN (Col2,Col3,Col4) AND
Col2 NOT IN (Col3,Col4) AND
Col3 <> Col4

SELECT DISTINCT * FROM tablename

SELECT DISTINCT col FROM tabl

SELECT * FROM
mytable
WHERE mytable.col1 != mytable.col2 != mytable.col3 ...

Related

postgresql - count distinct combination of three columns- order doesn't matter

I'm trying to count distinct combinations of three columns, order of the columns doesn't matter
sample :
a a a
a a b
a b a
b b a
b a b
the result I'm getting :
a a a 1
a a b 1
a b a 1
b b a 1
b a b 1
desired result
aaa 1
aab 2
bba 2
You can use an ordered array
select v[1], v[2], v[3], count(*) n
from tbl t
cross join lateral (
select array_agg(col order by col) v
from (
values (c1),(c2),(c3)
) t(col)
) s
group by v[1], v[2], v[3];
db<>fiddle
Maybe you can use checksums for getting the required result eg if it is really just combinations 'a' and 'b' that you are dealing with, you could convert the letters to integers (by calling the ASCII() function) and add these up so that you get a checksum.
TABLE
create table t (c1, c2, c3 ) as
select 'a', 'a', 'a' union all
select 'a', 'a', 'b' union all
select 'a', 'b', 'a' union all
select 'b', 'b', 'a' union all
select 'b', 'a', 'b' ;
Checksums
select c1, c2, c3, ascii( c1 ) + ascii( c2 ) + ascii( c3 ) as checksum
from t ;
-- output
c1 c2 c3 checksum
a a a 291
a a b 292
a b a 292
b b a 293
b a b 293
If this works for you, then you can use window functions eg
select c1, c2, c3, rc_ as rowcount
from (
select c1, c2, c3
, count(*) over ( partition by ascii( c1 ) + ascii( c2 ) + ascii( c3 ) order by 1 ) rc_
, row_number() over ( partition by ascii( c1 ) + ascii( c2 ) + ascii( c3 ) order by 1 ) rn_
from t
) sq
where rc_ = rn_ ;
-- output
c1 c2 c3 rowcount
a a a 1
a b a 2
b a b 2
See dbfiddle.
If you are dealing with strings that cannot easily converted to integers, you could create a mapping between the strings and integers, and implement the map_ as a view (so that it is easy to use in subsequent queries) eg
MAP
-- {1} find all distinct elements
-- {2} map each element to an integer
create view map_
as
select val_, rank() over ( order by val_ ) weight_
from (
select distinct val_
from (
select distinct c1 val_ from t union all
select distinct c2 from t union all
select distinct c3 from t
) all_elements
) unique_elements ;
Once you have this map, you can use its values for creating checksums (maybe also in a view) ...
Checksums
create view t_checksums_
as
select c1, c2, c3, c1weight + c2weight + c3weight as checksum
from (
select
c1, ( select weight_ from map_ where c1 = map_.val_ ) c1weight
, c2, ( select weight_ from map_ where c2 = map_.val_ ) c2weight
, c3, ( select weight_ from map_ where c3 = map_.val_ ) c3weight
from t
) valandweight ;
... and then, you can use the same query as before, for obtaining the final result - see dbfiddle.

oracle transposing rows to columns

my question is about transposing rows into columns.
I have got table T1(c1,c2,c3,c4,c5) columns with datatype varchar2, i want to transpose the rows obtained,
example:
select * from T1
gives
c1 c2 c3 c4 c5
row1 1 2 3 4 5
row2 A B C D E
....
rown U V W X Y
the result expected is
C1 1 A......U
C2 2 B......V
C3 3 C......W
C4 4 D......X
C5 5 E......Y
all rows in different columns(table contains only 10-15 rows)
i have tried the following query, but it isnt giving expected result.
Select RN,value
From (
Select x.*,row_number ()
Over ( Order By c1) rn From T1 x)
Unpivot (value For value_type In (C1,c2,c3,c4,c5)
);
So you only need to pivot data again:
dbfiddle demo
select *
from (
select rn, val, col
from (select t1.*, row_number() over (order by c1) rn from t1)
unpivot (val for col in (c1, c2, c3, c4, c5)))
pivot (max(val) for rn in (1, 2, 3, 4))
order by col
You have to know how many rows are in t1 and list them all in pivot in clause (1, 2, 3, 4) alternatively adding aliases for each column.

count of distinct columns in a record

How to count distinct columns values for a record
C1 C2 C3 C4
1 USER1 USER2 USER3
2 USER1 USER1 USER2
3 USER2 USER3 USER3
4 USER1 USER1 USER1
OUTPUT:
C1 COUNT
1 3
2 2
3 2
4 1
How to calculate distinct number of users in each record. Is there a way other than comparing column values.
Thanks.
One way is with unpivot:
select c1, count(distinct col) as cnt from (
select * from your_table
unpivot( col for lst in(C2, C3, C4) )
) tt
group by c1
For only three comparison columns this is the simplest thing which would work:
with cte as (
select c1, c2 from your_table
union
select c1, c3 from your_table
union
select c1, c4 from your_table
)
select c1, count(c2) as cnt
from cte
group by c1
/
The union operator produces a distinct set which feeds into the aggregated count.
with cte as (
select c1, c2 from your_table
union all
select c1, c3 from your_table
union all
select c1, c4 from your_table
)
select c1, count(c2) as cnt,count(distinct c2) as distinct_cnt
from cte
group by c1
/

SQL - find rows that have the same set of values in a column

I have a table and I want to select all rows that have exactly the same set of values that appear in a column and return them as a pair of a certain column.
For example, let's say I have a table named Table:
C1 C2
1 1
1 2
1 3
2 1
3 1
3 2
3 3
4 1
4 2
When I run my query, it should return the row:
1 3
because these are the two values in C1 that have the same set of values in column C2 (1,2,3).
I have an incorrect query below that returns all rows that have at least one matching value in C2 and I can't figure out how to correct it.
SELECT DISTINCT T1.C1, T2.C1
FROM Table T1, Table T2
WHERE T1.C1 != T2.C1
AND T1.C2 = T2.C2
AND T1.C1 < T2.C1
GROUP BY s1.suppId, s2.suppId;
Any help would be greatly appreciated, thanks.
As you do not specify, this one will handle the case of two sets of matching C2 values, outputting two rows - one for each matched set.
with thetable as (
SELECT 1 C1, 1 c2 from dual union
SELECT 1 C1, 2 c2 from dual union
SELECT 1 C1, 3 c2 from dual union
SELECT 2 C1, 1 c2 from dual union
SELECT 3 C1, 1 c2 from dual union
SELECT 3 C1, 2 c2 from dual union
SELECT 3 C1, 3 c2 from dual union
SELECT 4 C1, 1 c2 from dual union
SELECT 4 C1, 2 c2 from dual union
-- added fourrows to give a second set of matches
SELECT 5 C1, 1 c2 from dual union
SELECT 5 C1, 2 c2 from dual union
SELECT 6 C1, 1 c2 from dual union
SELECT 6 C1, 2 c2 from dual )
SELECT LIST_C2, List_c1
FROM (
SELECT list_c2
,LISTAGG(c1,',') WITHIN GROUP (ORDER BY c1) list_c1
FROM (
SELECT c1, LISTAGG(c2,',') WITHIN GROUP (ORDER BY c2) list_c2
FROM thetable
GROUP BY c1
)
group by list_c2
)
-- only bring back where we had more than one c1
WHERE instr(list_c1,',') != 0
Showing the following two sets of C2 values and their matching lists of C1s
LIST_C2 LIST_C1
"1,2" "4,5,6"
"1,2,3" "1,3"
listagg is the rescue (instead of count as commented by #Juan)
with lst as (
select c1, LISTAGG(c2, '; ') WITHIN GROUP (ORDER BY c2) c2_lst
from tst
group by c1
)
select lst1.c1 c1a, lst2.c1 c1b
from lst lst1
inner join lst lst2
on lst1.c2_lst = lst2.c2_lst and
lst1.c1 < lst2.c1
;
gives as requested
1 3
SQLFiddleDemo
Also be prepared, this works only small data (the concatenated key is limited with 4000 bytes).
UPDATE
listagg concatenates all values in the group. To get only distinct values (i.e. set of values) an additional query with DISTINCT must be performed.
WITH lst AS
( SELECT DISTINCT c1,c2 FROM tst
),
lst_dist AS
(SELECT c1,
LISTAGG(c2, '; ') WITHIN GROUP (
ORDER BY c2) c2_lst
FROM lst
GROUP BY c1
)
SELECT lst1.c1 c1a,
lst2.c1 c1b
FROM lst_dist lst1
INNER JOIN lst_dist lst2
ON lst1.c2_lst = lst2.c2_lst
AND lst1.c1 < lst2.c1
You can do this without list agg, using a self join:
select t1.c1, t2.c1
from (select t.*, count(*) over (partition by c1) as cnt
from table t
) t1 join
(select t.*, count(*) over (partition by c1) as cnt
from table t
) t2
on t1.c2 = t2.c2 and t1.c1 < t1.c2 and t1.cnt = t2.cnt
group by t1.c1, t2.c1
having count(*) = max(t1.cnt);
Note: this assumes that there are no duplicate rows in the table. A slight variation can work in that case as well.
This joins the rows on the second column and then aggregates by the first. Along the way, it makes sure that the number of matching columns is the same in the two table and that all columns match.

Cell to Cell comparison in Sql Server?

I have tbl1 :
Id | c1 | c2 | c3 |
____|_____|______|_______|_
1 a b c
____|_____|______|_______|_
2 h j k
____|_____|______|_______|_
3 t y u
____|_____|______|_______|_
I have tbl2 :
Id | c1 | c2 | c3 |
____|_____|______|_______|_
1 a b D
____|_____|______|_______|_
2 c c c
____|_____|______|_______|_
3 k l k
____|_____|______|_______|_
I need to compare each cell from tbl1 to its appropriate place in tbl2 :
the desired output is :
Id |tbl1 | tbl2 |
____|_____|______|
1 a a
____|_____|______|
1 b b
____|_____|______|
1 c d
____|_____|______|
2 h c
____|_____|______|
2 j c
____|_____|______|
2 k c
____|_____|______|
...
...
...
...
visual representation :
i tried many queries... but not succeed...
select T1.id, T1.tbl1, T2.tbl2
from (
select U.id, U.tbl1, U.col
from tbl1
unpivot (tbl1 for col in (c1, c2, c3)) U
) T1
inner join
(
select U.id, U.tbl2, U.Col
from tbl2
unpivot (tbl2 for col in (c1, c2, c3)) U
) T2
on T1.id = T2.id and
T1.col = T2.col
order by T1.id
First you should unpivot data:
select Id, C1, 'C1' as C from tbl1 union all
select Id, C2, 'C2' as C from tbl1 union all
select Id, C3, 'C2' as C from tbl1 union all
Then you can compare data:
select coalesce( uTbl1.Id,uTbl2.Id) as Id, uTbl1.C, uTbl2.C
from (
select Id, C1 as C, 'C1' as T from tbl1 union all
select Id, C2 as C, 'C2' as T from tbl1 union all
select Id, C3 as C, 'C3' as T from tbl1 ) uTbl1
full outer join (
select Id, C1 as C, 'C1' as T from tbl2 union all
select Id, C2 as C, 'C2' as T from tbl2 union all
select Id, C3 as C, 'C3' as T from tbl2 ) uTbl2
on uTbl1.Id = uTbl2.Id and uTbl1.T = uTbl2.T
Disclaimer:
- Not tested.
Edited With CTE:
; with
uTbl1 as (
select Id, C1 as C, 'C1' as T from tbl1 union all
select Id, C2 as C, 'C2' as T from tbl1 union all
select Id, C3 as C, 'C3' as T from tbl1 )
,uTbl2 as (
select Id, C1 as C, 'C1' as T from tbl2 union all
select Id, C2 as C, 'C2' as T from tbl2 union all
select Id, C3 as C, 'C3' as T from tbl2 )
select coalesce( uTbl1.Id,uTbl2.Id) as Id, uTbl1.C, uTbl2.C
from
uTbl1
full outer join
uTbl2
on uTbl1.Id = uTbl2.Id and uTbl1.T = uTbl2.T
Do 3 atomic subqueries and use then with UNION ALL to get the final result:
SELECT tbl1.id, tbl1.c1, tbl2.c1 FROM tbl1
INNER JOIN tbl2 on tbl1.id = tbl2.id
UNION ALL
SELECT tbl1.id, tbl1.c2, tbl2.c2 FROM tbl1
INNER JOIN tbl2 on tbl1.id = tbl2.id
UNION ALL
SELECT tbl1.id, tbl1.c3, tbl2.c3 FROM tbl1
INNER JOIN tbl2 on tbl1.id = tbl2.id
ORDER BY 1 --sort by column 1 (the IDs)