Reputation: 51
working in Oracle SQL and I have the following data set:
My goal is to get it into a dataset that looks like this, I'm assuming I will have to use some form of a pivot function, but I'm not sure how I would go about creating new column names that don't already exist in the same step:
I am only providing one example of my total dataset, there will be plenty of INDIV_ID records with a varying number of possible purchase dates (i.e., not every INDIV_ID will have 10 purchase dates. Some could have more, some could have less)
Thank you in advance,
Nick
Upvotes: 0
Views: 222
Reputation: 65408
You can use Conditional Aggregation in such a way that to create a select statement string to pivot those columns while enumerating through use of ROW_NUMBER()
function for each individual date in order to assign different integer value dynamically even if there exists equal date values within a stored function which returns a value in SYS_REFCURSOR
type such as
CREATE OR REPLACE FUNCTION Fn_Pivot_Table RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_cols VARCHAR2(32767);
BEGIN
SELECT LISTAGG( 'MAX(CASE WHEN rn = '||rn||' THEN prch_dt END ) AS "Date_'||rn||'"' , ',')
WITHIN GROUP ( ORDER BY rn )
INTO v_cols
FROM ( SELECT prch_dt,ROW_NUMBER() OVER (PARTITION BY indiv_id ORDER BY prch_dt) AS rn FROM t );
v_sql :='SELECT indiv_id,'|| v_cols ||
' FROM ( SELECT t.*,ROW_NUMBER() OVER (PARTITION BY indiv_id ORDER BY prch_dt) AS rn FROM t )
GROUP BY indiv_id';
OPEN v_recordset FOR v_sql;
RETURN v_recordset;
END;
/
where t
represents your table purchase date values of which needs to be pivoted.
Then call that function from the SQL Developer's console as
SQL> DECLARE
result SYS_REFCURSOR;
BEGIN
:result := Fn_Pivot_Table;
END;
/
SQL> PRINT result;
Upvotes: 0
Reputation: 1270843
You can do this if you know the number of columns you want:
select indiv_id,
max(case when seqnum = 1 then prch_dt end) as dt_1,
max(case when seqnum = 2 then prch_dt end) as dt_2,
. . .
from (select t.*,
row_number() over (partition by indiv_id order by prch_dt) as seqnum
from t
) t
group by indiv_id;
If you don't know the number of columns, then you need to use dynamic SQL -- which is quite cumbersome.
Alternatively, you could aggregate the values into a single delimited string:
select indiv_id,
list_agg(prch_dt, ',') within group (order by prch_dt)
from (select t.*,
row_number() over (partition by indiv_id order by prch_dt) as seqnum
from t
) t
group by indiv_id;
Upvotes: 2