How to get a similar value in Oracle - mysql

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.

Related

How to find unique pairs from two columns in SQL?

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
)

how to get the table column names as entries in result column set?

The database scheme consists:
Table1(code, col1, col2, col3, col4, col5)
What to do is:
For the Table1 with the maximal code value from Table1 table, obtain all its characteristics (except for a code) in two columns:
The name of the characteristic (a name of a corresponding column in the PC table);
Value of the characteristic.
I don't have any idea how to get the table column names in my result column set.
The final result will look like:
chr value
col1 133
col2 80
col3 28
col4 2
col5 50
This is an unpivot operation. The simplest way is using union all. However, the following is generally more efficient:
select (case when n.n = 1 then 'col1'
when n.n = 2 then 'col2'
when n.n = 3 then 'col3'
when n.n = 4 then 'col4'
when n.n = 5 then 'col5'
end) as chr,
(case when n.n = 1 then col1
when n.n = 2 then col2
when n.n = 3 then col3
when n.n = 4 then col4
when n.n = 5 then col5
end) as value
from table t cross join
(select 1 as n union all select 2 union all select 3 union all select 4 union all select 5
) n;
This is more efficient when your table is big or a complicated subquery.
The union all version is:
select 'col1', col1 from table t union all
select 'col2', col2 from table t union all
select 'col3', col3 from table t union all
select 'col4', col4 from table t union all
select 'col5', col5 from table t;
SELECT 'col1', MAX(col1) FROM table1
UNION
SELECT 'col2', MAX(col2) FROM table1
UNION
...
SELECT 'cd' as chr, cd as value
FROM pc
WHERE code = (SELECT max(code) FROM pc)
UNION
SELECT 'model' as chr, cast(model as varchar)as value
FROM pc
WHERE code = (SELECT max(code) FROM pc)
UNION
SELECT 'speed' as chr,cast(speed as varchar) as value
FROM pc
WHERE code = (SELECT max(code) FROM pc)
UNION
SELECT 'ram' as chr, cast(ram as varchar) as value
FROM pc
WHERE code = (SELECT max(code) FROM pc)
UNION
SELECT 'hd' as chr, cast(hd as varchar) as value
FROM pc
WHERE code = (SELECT max(code) FROM pc)
UNION
SELECT 'price' as chr,cast(price as varchar) as value
FROM pc
WHERE code = (SELECT max(code) FROM pc)
Select char, value
From
(Select code,
cast(speed as varchar(20)) speed,
cast(ram as varchar(20)) ram,
cast(hd as varchar(20)) hd,
cast(model as varchar(20)) model,
cast(cd as varchar(20)) cd,
cast(price as varchar(20)) price
FROM pc
) src
UNPIVOT
(value For char in (speed,ram,hd,model,cd,price)
) As unpvt
where
code in (Select max(code) from PC)`

How to delete ALL duplicate records (including the original)

Using SQL Server 2008 tsql, I'm trying to remove ALL the records in a table when a set of values recur. So if my table looked like this:
idcol1col2
1 A 1
2 A 1
3 A 2
4 B 1
5 B 1
6 B 2
Rows 1, 2, 4, 5 would all be deleted.
;WITH d AS
(
SELECT col1, col2, c = COUNT(*) OVER
(PARTITION BY col1, col2 ORDER BY col1)
FROM dbo.yourtable
)
DELETE d WHERE c > 1;
In fact it can be slightly tidier:
;WITH d AS
(
SELECT id, c = COUNT(*) OVER
(PARTITION BY col1, col2 ORDER BY col1)
FROM dbo.yourtable
)
DELETE d WHERE c > 1;
And I'll fess up, I tested the above on SQL Server 2012, however I forgot to change the fiddle to SQL Server 2008. For versions prior to SQL Server 2012, here is one variation:
;WITH d AS
(
SELECT col1, col2
FROM dbo.yourtable AS t
GROUP BY col1, col2
HAVING COUNT(*) > 1
)
DELETE t --*
FROM dbo.yourtable AS t
WHERE EXISTS
(
SELECT 1 FROM d
WHERE col1 = t.col1 AND col2 = t.col2
);
You'd think it would be sufficient to just DELETE d; here but you get:
Msg 4403, Level 16, State 1, Line 2
Cannot update the view or function 'd' because it contains aggregates, or a DISTINCT or GROUP BY clause, or PIVOT or UNPIVOT operator.
Try this:
DELETE t
FROM dbo.yourTabe t
JOIN (
SELECT col1,col2,COUNT(1) cnt
FROM dbo.YourTable
GROUP BY col1, col2
HAVING COUNT(1)>1
) s
ON t.col1 = s.col1
AND t.col2 = s.col2

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