SELECT * FROM
(
SELECT TEST_NAME, SBNO, VAL
FROM TABLE1
)
PIVOT (
MAX(VAL)
FOR SBNO in (1 value1, 2 value2, 3 value3 ));
Output:
I want to show data in ascending order, like this:
2.3 , 2.4 , 2.5
but result is
2.3 , 2.5 , 2.4
This would do the trick. I have created a new SBNO column, ordering by test_name and value and then PIVOT operator will do the rest.
;with cte as (
select
test_name
,val
,'Value' + cast(ROW_NUMBER() over (partition by test_name order by test_name, val) as varchar(5)) as new_SBNO
from TABLE1
)
select *
from cte
pivot (
max(val)
for new_SBNO in (value1, value2, value3)
) pvt
I would do this using conditional aggregation:
select test_name,
max(case when seqnum = 1 then val end) as value_1,
max(case when seqnum = 2 then val end) as value_2,
max(case when seqnum = 3 then val end) as value_3
from (select t1.*,
row_number() over (partition by test_name order by val asc) as seqnum
from table1 t1
) t1
group by test_name;
You could express this with pivot. And in Oracle, pivot can even be a bit faster. I just find conditional aggregation to be more flexible and simpler to implement.
Related
My problem is that I would like to select some records which appears in a row.
For example we have table like this:
x
x
x
y
y
x
x
y
Query should give answer like this:
x 3
y 2
x 2
y 1
SQL tables represent unordered sets. Your question only makes sense if there is a column that specifies the ordering. If so, you can use the difference-of-row-numbers to determine the groups and then aggregate:
select col1, count(*)
from (select t.*,
row_number() over (order by <ordering col>) as seqnum,
row_number() over (partition by col1 order by <ordering col>) as seqnum_2
from t
) t
group by col1, (seqnum - seqnum_2)
I made a SQL Fiddle
http://sqlfiddle.com/#!18/f8900/5
CREATE TABLE [dbo].[SomeTable](
[data] [nchar](1) NULL,
[id] [int] IDENTITY(1,1) NOT NULL
);
INSERT INTO SomeTable
([data])
VALUES
('x'),
('x'),
('x'),
('y'),
('y'),
('x'),
('x'),
('y')
;
select * from SomeTable;
WITH SomeTable_CTE (Data, total, BaseId, NextId)
AS
(
SELECT
Data,
1 as total,
Id as BaseId,
Id+1 as NextId
FROM SomeTable
where not exists(
Select * from SomeTable Previous
where Previous.Id+1 = SomeTable.Id
and Previous.Data = SomeTable.Data)
UNION ALL
select SomeTable_CTE.Data, SomeTable_CTE.total+1, SomeTable_CTE.BaseId as BaseId, SomeTable.Id+1 as NextId
from SomeTable_CTE inner join SomeTable on
SomeTable.Data = SomeTable_CTE.Data
and
SomeTable.Id = SomeTable_CTE.NextId
)
SELECT Data, max(total) as total
FROM SomeTable_CTE
group by Data, BaseId
order by BaseId
The elephant in the room is the missing column(s) to establish the order of rows.
SELECT col1, count(*)
FROM (
SELECT col1, order_column
, row_number() OVER (ORDER BY order_column)
- row_number() OVER (PARTITION BY col1 ORDER BY order_column) AS grp
FROM tbl
) t
GROUP BY col1, grp
ORDER BY min(order_column);
To exclude partitions with only a single row, add a HAVING clause:
SELECT col1, count(*)
FROM (
SELECT col1, order_column
, row_number() OVER (ORDER BY order_column)
- row_number() OVER (PARTITION BY col1 ORDER BY order_column) AS grp
FROM tbl
) t
GROUP BY col1, grp
HAVING count(*) > 1
ORDER BY min(order_column);
db<>fiddle here
Add a final ORDER BY to maintain original order (and a meaningful result). You may want to add a column like min(order_column) as well.
Related:
Find the longest streak of perfect scores per player
Select longest continuous sequence
Group by repeating attribute
Might be easy for you expert but I am finding a challenge here-
My column data is as like below, I need to separate out the value which is inside bracket(). My string pattern would always be like this.
J Zeneta (A50103050); S Rao (B499487)
Output should be
Col1 Col2
A50103050 B499487
You can try this, it might need tweaking depending on your RDBMS, this is for SQLServer
select Left(value, CharIndex(')',value)-1) from (
select value from String_Split('J Zeneta (A50103050); S Rao (B499487)','(')
where value like '%)%'
)x
Edit
To have columns a simple case can yeild, like so
select max(case when rn=1 then Value end) Col1, max(case when rn=2 then value end) Col2 from (
select Left(value, CharIndex(')',value)-1) [Value], Row_Number() over (order by (select null)) rn from (
select value from String_Split('J Zeneta (A50103050); S Rao (B499487)','(')
where value like '%)%'
)x
)x
Edit 2
Using data from an existing table example
create table #Test (id int, col varchar(50))
insert into #Test select 1, 'J Zeneta (A50103050); S Rao (B499487)'
insert into #Test select 2, 'Bob Builder (12345); Mr Rambo (67890)'
select id, max(case when (rn % 2)=0 then Value end) Col1, max(case when (rn % 2)!=0 then value end) Col2 from (
select id, Left(value, CharIndex(')',value)-1) [Value], Row_Number() over (order by (select null)) rn from (
select id, value
from #Test t cross apply String_Split(t.col,'(')
where value like '%)%'
)x
)x
group by id
there is a table with
1001 vsp,science,BBA 25-05-2020
1001 vsp,Maths,Btech 26-05-2020
1001 vsp,Maths,Btech 27-05-2020
1002 hyd,science,BBA 24-05-2020
1002 blr,Maths,Btech 25-05-2020
I want
1001 vsp,science,bba vsp,Maths,Btech vsp,Maths,Btech
You need one of my favorite combo to achieve your goal:
CTE (to create proper sub request): https://learn.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql
ROW_NUMBER (to rank your rows): https://learn.microsoft.com/en-us/sql/t-sql/functions/row-number-transact-sql
PIVOT (to pivot your results): https://learn.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot
And now the solution:
WITH orderedCourse AS
(
SELECT GroupId,
CourseLabel,
ROW_NUMBER() OVER (PARTITION BY GroupId ORDER BY CourseDate) AS CourseNumber
FROM #myCourses
)
SELECT TOP (1) GroupId, [1], [2], [3], [4]
FROM
(
SELECT GroupId,
CourseLabel,
CourseNumber
FROM orderedCourse
) AS src
PIVOT
(
MIN(CourseLabel) -- default agregate
FOR CourseNumber IN ([1], [2], [3], [4] /*... if you have more courses by group*/)
) AS pvt
ORDER BY GroupId
Which give the result:
1001 vsp,science,BBA vsp,Maths,Btech vsp,Maths,Btech NULL
I used this code to declare the table:
INSERT INTO #myCourses
SELECT 1001, 'vsp,science,BBA', CAST('25-05-2020' AS date) UNION ALL
SELECT 1001, 'vsp,Maths,Btech', CAST('26-05-2020' AS date) UNION ALL
SELECT 1001, 'vsp,Maths,Btech', CAST('27-05-2020' AS date) UNION ALL
SELECT 1002, 'yd,science,BBA', CAST('24-05-2020' AS date) UNION ALL
SELECT 1002, 'blr,Maths,Btech', CAST('25-05-2020' AS date);
SELECT GroupId,
CourseLabel,
CourseDate,
ROW_NUMBER() OVER (PARTITION BY GroupId ORDER BY CourseDate) AS CourseNumber
FROM #myCourses;
Just use conditional aggregation with row_number():
select col1,
max(case when seqnum = 1 then col2 end),
max(case when seqnum = 2 then col2 end),
max(case when seqnum = 3 then col2 end)
from (select t.*,
row_number() over (partition by col1 order by col3) as seqnum
from t
) t
group by col1;
This has nothing to do with string aggregation. It also doesn't require a plethora of subqueries and CTEs.
I am trying to write a query to transpose rows to columns. The attached image has a sample table which I want to transpose and expected output.
Any input is appreciated.
Option 1. Conditional aggregation
select labid, subjectid,
max(case when timepoint='T0' then val1 end) T0_val1,
max(case when timepoint='T0' then val2 end) T0_val2,
max(case when timepoint='T1' then val1 end) T1_val1,
max(case when timepoint='T1' then val2 end) T1_val2
from input
group by labid, subjectid;
Option 2. Unpivot/Pivot
select * from
(
select labid, subjectid, timepoint+'_'+col as timepoint_col, val
from
(select labid, subjectid, timepoint, val1, val2
from input) as src
unpivot
(
val for col in (val1, val2)
) as unpiv) as x
pivot
(
max(val)
for timepoint_col in ([T0_val1],[T0_val2],[T1_val1],[T1_val2])
) as piv1
I want to convert a series of rows into a series of columns
create table #cusphone(cusid int,cusph1 int)
insert into #cusphone values(1,48509)
insert into #cusphone values(1,48508)
insert into #cusphone values(1,48507)
insert into #cusphone values(2,48100)
so that the output is like this
1 48509 48508 48507
2 48100 null null
You can use the same approach of rank() and then use the new PIVOT function as follows:
with cusCte as(
select cusid,cusph1,RANK() over (partition by cusid order by cusph1) r
from #cusphone)
SELECT cusid, [1] AS C1, [2] AS C2, [3] AS C3
FROM
(SELECT cusid,cusph1,r
FROM cusCte) p
PIVOT
(
MIN (cusph1)
FOR r IN
( [1], [2], [3] )
) AS pvt;
You did not specify the rules by which something should appear in the first column vs the second column so I guessed that this is based on the occurrence (and thus sorting) of the cusph1 value.
With RankedItems As
(
Select cusid, cusph1
, ROW_NUMBER() OVER( PARTITION BY cusid ORDER BY cusph1 DESC) As Num
From #cusphone
)
Select cusid
, Min(Case When Num = 1 Then cusph1 End) As Col1
, Min(Case When Num = 2 Then cusph1 End) As Col2
, Min(Case When Num = 3 Then cusph1 End) As Col3
From RankedItems
Group By cusid