column to row for only one column - sql

I have only one column in my table having all distinct values I need to group it into pairs of 3 and make 3 columns out of 3 rows please help
Source
COL1
-----
A
B
C
D
E
F
Required output 1:
COL1
------
A,B,C
D,E,F
Required output 2:
col1 col2 col3
---- ---- ----
A B C
D E F

Output 1:
select listagg(col1, ',') within group (order by col1) as col
from (
select col1,
case
when row_number() over (order by col1) <= (count(*) over ()) / 2 then 0
else 1
end as grp
from foo
)
group by grp
order by grp;
For Output 2:
select max(col1) as col1,
max(col2) as col2,
max(col3) as col3
from (
select case mod(row_number() over (order by col1),3)
when 1 then col1
else null
end as col1,
case mod(row_number() over (order by col1),3)
when 2 then col1
else null
end as col2,
case mod(row_number() over (order by col1),3)
when 0 then col1
else null
end as col3,
case
when row_number() over (order by col1) <= (count(*) over ()) / 2 then 0
else 1
end as grp
from foo
)
group by grp
order by grp;
SQLFiddle example: http://sqlfiddle.com/#!4/d699c/1

Please try below query for second solution:
select Col1, Col2, Col3 From(
select
ceil(row_number() over(order by Col1)/3) Rnum,
mod(row_number() over(order by Col1)+2, 3)+1 Row_Num,
COl1
from
YourTable
)x pivot (min(Col1) for Row_Num in ('1' as Col1, '2' as Col2, '3' as Col3));
Fiddle Demo

Another way (will work for every multiple of 3 of records)
output1
select listagg(col1, ',') within group (order by col1) col1
from
(select col1, row_number() over(order by col1) rn
from t) tt
group by rn - decode(mod (rn, 3) ,0,3,mod (rn, 3));
output2
select c2_col col1, c3_col col2, c1_col col3
from
(select rn - decode(mod (rn, 3) ,0,3,mod (rn, 3)) grp, mod(rn, 3) rnm, col1
from
(select col1, row_number() over(order by col1) rn
from t)) tt
pivot
(
max(col1) as col
for rnm in (0 as c1,1 c2,2 c3)
);
Here is a sqlfiddle demo

Related

Select equal number of random rows with respect to a column

Consider I have a table like this
Col1 || Col2
-------------
a || 0
b || 0
c || 1
d || 1
e || 0
How can I select rows from it so that I have equal number of 1s and 0s, like below can be a result
Col1 || Col2
-------------
a || 0
c || 1
d || 1
e || 0
The rows removed/left out are at random and deleting from an existing table would work as well.
For each col2 partition, you can give each row a row number and then find those rows where there is only one instance of the row number and delete them:
DELETE FROM table_name
WHERE ROWID IN (
SELECT MIN(ROWID)
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY col2 ORDER BY DBMS_RANDOM.VALUE)
AS rn
FROM table_name
)
GROUP BY rn
HAVING COUNT(*) < 2
);
If you just want to SELECT the rows then you can use a similar technique:
SELECT col1, col2
FROM (
SELECT col1,
col2,
COUNT(*) OVER (PARTITION BY rn) AS cnt
FROM (
SELECT col1,
col2,
ROW_NUMBER() OVER (PARTITION BY col2 ORDER BY DBMS_RANDOM.VALUE)
AS rn
FROM table_name
)
)
WHERE cnt = 2;
db<>fiddle here
How can I select rows from it so that I have equal number of 1s and 0s?
Yet another option might be to count COL2 values and use least of those two (as the final result has to have equal number of 0s and 1s) in a UNION set operation. Something like this:
Sample data:
SQL> select * from test;
COL1 COL2
---- ----------
a 0
b 0
c 1
d 1
e 0
Query & result:
SQL> with cnts as
2 -- count rows by COL2 value
3 (select sum(case when col2 = 0 then 1 else 0 end) cnt_0,
4 sum(case when col2 = 1 then 1 else 0 end) cnt_1
5 from test
6 )
7 select t.* from test t cross join cnts c
8 where t.col2 = 0 and rownum <= least(c.cnt_0, c.cnt_1)
9 union all
10 select t.* from test t cross join cnts c
11 where t.col2 = 1 and rownum <= least(c.cnt_0, c.cnt_1);
COL1 COL2
---- ----------
a 0
b 0
c 1
d 1
SQL>
You can do this with only one subquery/CTE. The following returns the smaller number of 0s and 1 (which determines the number of rows being returned):
least( sum(col2), sum(1 - col2) ) as num_rows
Then, you can incorporate this into a window function with row_number():
select col1, col2
from (select t.*,
least(sum(col2) over (), sum(1-col2) over ()) as num_rows,
row_number() over (partition by col2 order by dbms_random.value) as seqnum
from t
) t
where seqnum <= num_rows;
use the window function to count the frequency of col2 and row number over col2. Then get the minimum frequency from it. Later get the rows with rownum less than or equal to min frequency.
with data AS
(
SELECT *, row_number() over(partition by col2 order by dbms_random.value()) as rownum, COUNT(*) over(partition by col2) freq from test
),
data2 as
(
SELECT min(freq) as cnt from data
)
SELECT col1, col2 from data,data2 where rownum <= cnt
This analytic function check if there are more zeroes or ones in the table
sum(decode(col2,0,-1,col2)) over()
Depending on the result use cumulative sum starting with that value of col2 that appears in lower count and mapping (using decode) it to -1, the other value is mapped to 1.
The filter is done on cum_sum <= 0 i.e. you get the same number of 0 and 1.
with t1 as (
select
col1, col2,
case when sum(decode(col2,0,-1,col2)) over() <= 0 then
/* more zeroes */
sum(decode(col2,0,1,1,-1)) over(order by col2 desc, col1)
else
sum(decode(col2,0,-1,col2)) over(order by col2 , col1)
end as cum_sum
from tab)
select col1, col2
from t1
where cum_sum <= 0;

If two rows have same id but different col2, how can you keep only the ones that have max col3?

I have a table with three columns (id, col2, col3, col4) where col2 is A or B and col3 and col4 are integers. My problem is, there are many columns that have the same id and a different col2 value, and I want to select ONLY the rows that have a maximum value in col3.
For instance, if we have:
id | col2 | col3 | col4
1 | A | 3 | 2
1 | B | 5 | 3
2 | A | 6 | 2
...
I want to keep only the tuple (1, B, 5, 3). How can I achieve this?
I've tried this:
SELECT id, col2, MAX(col3), col4 FROM t GROUP BY id;
but I get an error saying that this is not a valid GROUP BY statement.
You can use keep:
SELECT id,
MAX(col2) KEEP (DENSE_RANK FIRST ORDER BY col3 DESC) as col2
MAX(col3),
MAX(col4) KEEP (DENSE_RANK FIRST ORDER BY col3 DESC) as col4
FROM t
GROUP BY id;
Or:
SELECT id, col2, col3, col4
FROM (SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY col3 DESC) as seqnum
FROM t
) t
WHERE seqnum = 1;
This query:
select t.*
from tablename t inner join (
select id, max(col3) col3
from tablename
group by id
having count(distinct col2) > 1
) g on g.id = t.id and g.col3 = t.col3
returns for each id that has different values in col2 only 1 row: the one containing the maximum value of col3.
If you also want the other rows where each id does not have different values in col2, then use UNION ALL:
select t.*
from tablename t inner join (
select id, max(col3) col3
from tablename
group by id
having count(distinct col2) > 1
) g on g.id = t.id and g.col3 = t.col3
union all
select t.* from tablename t
where not exists (
select 1 from tablename
where id = t.id and col2 <> t.col2
)
select * from TableName where col3 = (select max(col3) from TableName)

SQL - Two Columns into One Distinct Ordered Column

If I have a table like this:
Col 1 | Col 2
-------------
A | 1
A | 2
B | 1
C | 1
C | 2
C | 3
How can I write a query to pull one column that looks like this --
Col 1
------
A
1
2
B
1
C
1
2
3
SELECT col1
FROM Some_Table_You_Did_Not_Name
UNION ALL
SELECT col2
FROM Some_Table_You_Did_Not_Name
If the order matters in your example then you want this:
WITH data AS
(
SELECT col1, col2, ROW_NUMBER() OVER (ORDER BY col1, col2) as RN
FROM Some_Table_You_Did_Not_Name
)
SELECT col
FROM (
SELECT DISTINCT col1 as col, RN, 1 as O
FROM data
UNION ALL
SELECT DISTINCT col2 as col, RN, 2 as O
FROM data
) JC_IS_THAT_GUY
ORDER BY RN ASC, O ASC, col ASC
You can use a query like the following:
SELECT Col1
FROM (
SELECT DISTINCT Col1, Col1 AS Col2, 0 AS grp
FROM mytable
UNION ALL
SELECT Col2 AS Col1, Col1 AS Col2, 1 AS grp
FROM mytable) AS t
ORDER BY Col2, grp, Col1
Demo here
There is absolutely no need to do a UNION, UNION ALL or reference the table more than once to unpivot data...
-- if Col2 is always a well ordered sequense like the test data...
SELECT
Col1 = x.Value
FROM
#TestData td
CROSS APPLY ( VALUES (IIF(td.Col2 = 1, td.Col1, NULL)), (CAST(td.Col2 AS CHAR(1))) ) x (Value)
WHERE
x.Value IS NOT NULL;
-- if it isn't...
WITH
cre_Add_RN AS (
SELECT
td.Col1,
td.Col2,
RN = ROW_NUMBER() OVER (PARTITION BY td.Col1 ORDER BY td.Col2)
FROM
#TestData td
)
SELECT
x.Value
FROM
cre_Add_RN arn
CROSS APPLY ( VALUES (IIF(arn.RN = 1, arn.Col1, NULL)), (CAST(arn.Col2 AS CHAR(1))) ) x (Value)
WHERE
x.Value IS NOT NULL;
HTH,
Jason

Oracle Group by based on next row value

We are trying to get a group by result by checking the next rows value.
Sample Data:
Table A
COL1 COL2 COL3
---- ---- ----
B BUY 1
B SELL 1.2
B SELL 2
C BUY 3
C SELL 4
C BUY 5
Result:
COL1 COL2 COUNT(1)
---- ---- --------
B BUY 1
B SELL 2
C BUY 1
C SELL 1
C BUY 1
You appear to have ordered by COL3; if this is the case then:
SELECT col1,
col2,
change - COALESCE( LAG( change ) OVER ( PARTITION BY col1 ORDER BY change ), 0 )
AS cnt
FROM (
SELECT col1,
col2,
CASE LEAD( col2 ) OVER ( PARTITION BY col1 ORDER BY col3 )
WHEN col2
THEN NULL
ELSE ROW_NUMBER() OVER ( PARTITION BY col1 ORDER BY col3 )
END AS change
FROM a
)
WHERE change IS NOT NULL;
If I understand correctly, you can do this with a difference of row numbers approach:
select col1, col2, count(*)
from (select t.*,
row_number() over (partition by col1 order by col3) as seqnum,
row_number() over (partition by col1, col2 order by col3) as seqnum_2,
from t
) t
group by col1, col2, (seqnum - seqnum_2);
This identifies groups of adjacent col2 values based on the ordering in col3.

How to get the following output?

How to get the following output ?
Input:
t1
-----------------
col1 col2
----------------
2 a
1 c
3 b
----------------
Output:
t1
-----------------
col1 col2
----------------
1 a
2 b
3 c
----------------
You can try using row number like:
SELECT row_number() OVER (ORDER BY a.col2) as col1, col2
FROM t1 a ORDER BY a.col2
select C1.col1, C2.col2
from
(select col1, row_number() over (order by col1) rn
from t1) C1
join
(select col2, row_number() over (order by col2) rn
from t1) C2
on C1.rn=C2.rn
order by C1.rn
I think following query may help you.
SELECT * FROM t1 ORDER BY col1 ;
please check this link for more practice
http://www.sqlfiddle.com/#!3/2e3e9/1/0
Try this..
select col1,col2 from
(select col1,rownum rn from(select col1 from t1 order by col1)) a,
(select col2,rownum rn from(select col2 from t1 order by col2)) b
where a.rn=b.rn