Oracle normalize multiple rows into new view - sql

I need to find a solution for the following problem.
Out internal postman has to scan a QR-barcode on a mailbox first and a datamatrix-barcode on each (internal) letter he puts into the mailbox.
The data from his scanner-device is stored into a Oracle 11g database-table in the following format
|----|---------------------|--------------|---------------|
| ID | SCAN_DATE | BAROCDE_TYPE | BARCODE_VALUE |
----------------------------------------------------------|
| 1 | 2016/02/01 08:10:30 | QR | Dept_HR |
| 2 | 2016/02/01 08:10:35 | DM | Lett_1 |
| 3 | 2016/02/01 08:10:38 | DM | Lett_3 |
| 4 | 2016/02/01 08:10:41 | DM | Lett_6 |
| 5 | 2016/02/01 08:16:37 | QR | Dept_FI |
| 6 | 2016/02/01 08:16:38 | DM | Lett_2 |
| 7 | 2016/02/01 08:16:40 | DM | Lett_4 |
|----|---------------------|--------------|---------------|
I want to "normalize?" the data into a database-view in the following format
(where it easy to see which letter was delivered to which mailbox)
|---------------------|------------|---------------------|----------|
| ScanDate Postbox | Department | ScanDate Letter | LetterID |
|---------------------|------------|---------------------|----------|
| 2016/02/01 08:10:30 | Dept_HR | 2016/02/01 08:10:35 | Lett_1 |
| 2016/02/01 08:10:30 | Dept_HR | 2016/02/01 08:10:38 | Lett_3 |
| 2016/02/01 08:10:30 | Dept_HR | 2016/02/01 08:10:41 | Lett_6 |
| 2016/02/01 08:16:37 | Dept_FI | 2016/02/01 08:16:38 | Lett_2 |
| 2016/02/01 08:16:37 | Dept_FI | 2016/02/01 08:16:40 | Lett_4 |
|---------------------|------------|---------------------|----------|
Any ideas how I can create an oracle database-view showing the data as described above?

I guess the Postbox record is the previous record to the letter records. This is a bad because unsafe association.
the following select should do the job:
-- Your testdata
with data(id,
scan_date,
barcode_type,
barcode_value) as
(select 1,
to_date('2016/02/01 08:10:30', 'YYYY/MM/DD HH24:MI:SS'),
'QR',
'Dept_HR'
from dual
union all
select 2,
to_date('2016/02/01 08:10:35', 'YYYY/MM/DD HH24:MI:SS'),
'DM',
'Lett_1'
from dual
union all
select 3,
to_date('2016/02/01 08:10:38', 'YYYY/MM/DD HH24:MI:SS'),
'DM',
'Lett_3'
from dual
union all
select 4,
to_date('2016/02/01 08:10:41', 'YYYY/MM/DD HH24:MI:SS'),
'DM',
'Lett_6'
from dual
union all
select 5,
to_date('2016/02/01 08:16:37', 'YYYY/MM/DD HH24:MI:SS'),
'QR',
'Dept_FI'
from dual
union all
select 6,
to_date('2016/02/01 08:16:38', 'YYYY/MM/DD HH24:MI:SS'),
'DM',
'Lett_2'
from dual
union all
select 7,
to_date('2016/02/01 08:16:40', 'YYYY/MM/DD HH24:MI:SS'),
'DM',
'Lett_4'
from dual)
-- Select
select dp.scan_date as "ScanDate Postbox",
dp.barcode_value as "Departement",
d.scan_date as "ScanDate Letter",
d.barcode_value as "LetterId"
from data dp, data d
where d.barcode_type = 'DM'
and dp.barcode_type = 'QR'
and dp.scan_date =
(select max(dpp.scan_date)
from data dpp
where dpp.barcode_type = dp.barcode_type
and dpp.scan_date <= d.scan_date);

Related

make recent log agg with unix timestamp in BigQuery

I'm making a webpage user access log table in BigQuery.
But I don't know how agg log with exit_time.
I want recent 5 view page log array.
If view page log is less than 5, the array is shorter.
plz teach me.
USER_EXIT_LOG AS (
SELECT
['A','A','B'] AS user_id,
[1000,2000,1000] AS exit_time
),
VIEW_PAGE_LOG AS (
SELECT
['A','A','A','A','A','B','B'] AS user_id,
['a','b','c','d','e','a','b'] AS view_page_id,
[800,900,1800,1900,1950,800,900] AS time
)
USER_EXIT_LOG
| user_id | exit_time |
| -------- | --------- |
| A | 1000 |
| A | 2000 |
| B | 1000 |
VIEW_PAGE_LOG
| user_id | view_page_id | view_time |
| -------- | ----------- | --------- |
| A | a | 800 |
| A | b | 900 |
| A | c | 1800 |
| A | d | 1900 |
| B | a | 800 |
| B | b | 900 |
WHAT I WANT
| user_id | exit_time | view_page_array |
| ------- | --------- | --------------- |
| A | 1000 | [b,a] |
| A | 2000 | [e,d,c] |
| B | 1000 | [b,a] |
Consider below
select u.user_id, exit_time,
array_agg(view_page_id order by view_time desc limit 5) as view_page_array
from (
select user_id, exit_time,
ifnull(lag(exit_time + 1) over(partition by user_id order by exit_time), 0) start_time
from `project.dataset.USER_EXIT_LOG`
) u
join `project.dataset.VIEW_PAGE_LOG` v
on u.user_id = v.user_id
and view_time between start_time and exit_time
group by user_id, exit_time
If applied t sample data in your question
with `project.dataset.USER_EXIT_LOG` as (
select 'A' user_id, 1000 exit_time union all
select 'A', 2000 union all
select 'B', 1000
), `project.dataset.VIEW_PAGE_LOG` as (
select 'A' user_id, 'a' view_page_id, 800 view_time union all
select 'A', 'b', 900 union all
select 'A', 'c', 1800 union all
select 'A', 'd', 1900 union all
select 'A', 'e', 1950 union all
select 'B', 'a', 800 union all
select 'B', 'b', 900
)
the output is

Partition two dates by month

I need to partition a range between two dates when the month of end date is different from the month of start date, using SQL in Oracle 11gXE.
For example:
SELECT ATIVOID, OSID, DT_INI, DT_FIM
FROM V_MTBF
WHERE ATIVOID IN ('12345TC','TCCS011701160001');
+------------------+-------------+-------------------+--------------------+
| ATIVOID | OSID | DT_INI | DT_FIM |
+------------------+-------------+-------------------+--------------------+
| 12345TC | 1710201409 | 20/10/17 14:09:58 | 01/12/17 09:03:52 |
| TCCS011701160001 | 1710201112 | 20/10/17 11:12:42 | 30/11/17 16:23:13 |
+------------------+-------------+-------------------+--------------------+
I would like to see:
+------------------+------------+-------------------+-------------------+
| ATIVOID | OSID | DT_INI | DT_FIM |
+------------------+------------+-------------------+-------------------+
| 12345TC | 1710201409 | 20/10/17 14:09:58 | 31/10/17 23:59:59 |
| 12345TC | 1710201409 | 01/11/17 00:00:00 | 30/11/17 23:59:59 |
| 12345TC | 1710201409 | 01/12/17 00:00:00 | 01/12/17 09:03:52 |
| TCCS011701160001 | 1710201112 | 20/10/17 11:12:42 | 31/10/17 23:59:59 |
| TCCS011701160001 | 1710201112 | 01/11/17 00:00:00 | 30/11/17 16:23:13 |
+------------------+------------+-------------------+-------------------+
I appreciate any help.
Try with below, Replace the static values to column and table name.
WITH TEMP_CTE(ATIVOID, OSID, DT_INI,DIF_M, LVL, DT_FIM)
AS
(SELECT '12345TC' AS , '1710201409' AS OSID, TO_DATE('20/10/17 14:09:00', 'DD/MM/YYYY HH24:MI:SS') AS DT_INI,
ABS(EXTRACT(MONTH FROM TO_DATE('20/10/17 14:09:58', 'DD/MM/YYYY HH24:MI:SS'))- EXTRACT(MONTH FROM TO_DATE('01/12/17 09:03:52', 'DD/MM/YYYY HH24:MI:SS'))) AS DIF_M,
1,
TO_DATE('01/12/17 09:03:52', 'DD-MM-YYYY HH24:MI:SS' ) AS DT_FIM
FROM DUAL
UNION ALL
SELECT ATIVOID, OSID, ADD_MONTHS(DT_INI, 1) AS DT_INI,
DIF_M, LVL + 1, DT_FIM FROM TEMP_CTE WHERE LVL <= DIF_M
)
SELECT ATIVOID, OSID,
CASE WHEN LVL = 1 THEN TO_CHAR(DT_INI, 'DD-MM-YYYY HH24:MI:SS') ELSE TO_CHAR(TRUNC(DT_INI, 'MM'), 'DD-MM-YYYY HH24:MI:SS') END AS DT_INI,
CASE WHEN LVL <= DIF_M THEN TO_CHAR(TRUNC(LAST_DAY(DT_INI) + 1) - 1/(24*60*60), 'DD-MM-YYYY HH24:MI:SS') ELSE TO_CHAR(DT_FIM, 'DD-MM-YYYY HH24:MI:SS') END AS DT_FIM FROM TEMP_CTE

How use Group by and Max(date) multi record

i want Group by by Max(Datetime) each record. but i query have dupplicatate record. i want don't duplicate record.
SQL:
select a.pmn_code,
a.ref_period,
a.SERVICE_TYPE,
min(a.status) keep (dense_rank last order by a.updated_dtm) as status,
max(a.updated_dtm) as updated_dtm
from tempChkStatus a
group by a.pmn_code, a.ref_period, a.SERVICE_TYPE
Data Table tempChkStatus:
PMN_CODE | REF_PERIOD | SERVICE_TYPE | STATUS | UPDATED_DTM
A | 01/2016 | OI | I | 19/08/2016 10:54:44
A | 01/2016 | OP | N | 06/06/2017 15:09:55
A | 02/2016 | OT | I | 31/08/2016 08:37:45
A | 02/2016 | OT | N | 12/10/2016 11:13:56
A | 04/2016 | OI | I | 19/08/2016 10:54:44
A | 04/2016 | OP | N | 06/06/2017 15:09:55
Result SQL:
PMN_CODE | REF_PERIOD | SERVICE_TYPE | STATUS | UPDATED_DTM
A | 01/2016 | OI | I | 19/08/2016 10:54:44
A | 01/2016 | OP | N | 06/06/2017 15:09:55
A | 02/2016 | OT | N | 12/10/2016 11:13:56
A | 04/2016 | OI | I | 19/08/2016 10:54:44
A | 04/2016 | OP | N | 06/06/2017 15:09:55
But I want Result:
PMN_CODE | REF_PERIOD | SERVICE_TYPE | STATUS | UPDATED_DTM
A | 01/2016 | OP | N | 06/06/2017 15:09:55
A | 02/2016 | OT | N | 12/10/2016 11:13:56
A | 04/2016 | OP | N | 06/06/2017 15:09:55
Help me please. Thanks advance ;)
with tempChkStatus (
PMN_CODE, REF_PERIOD , SERVICE_TYPE , STATUS , UPDATED_DTM) as
(
select 'A', '01/2016' ,'OI', 'I', to_date('19/08/2016 10:54:44', 'dd/mm/yyyy hh24:mi:ss') from dual union all
select 'A', '01/2016' ,'OP', 'N', to_date('06/06/2017 15:09:55', 'dd/mm/yyyy hh24:mi:ss') from dual union all
select 'A', '02/2016' ,'OT', 'I', to_date('31/08/2016 08:37:45', 'dd/mm/yyyy hh24:mi:ss') from dual union all
select 'A', '02/2016' ,'OT', 'N', to_date('12/10/2016 11:13:56', 'dd/mm/yyyy hh24:mi:ss') from dual union all
select 'A', '04/2016' ,'OI', 'I', to_date('19/08/2016 10:54:44', 'dd/mm/yyyy hh24:mi:ss') from dual union all
select 'A', '04/2016' ,'OP', 'N', to_date('06/06/2017 15:09:55', 'dd/mm/yyyy hh24:mi:ss') from dual
)
select * from (
select e.*, max(updated_dtm) over (partition by ref_period) md from tempchkstatus e
)
where updated_dtm = md
;
You just need to remove SERVICE_TYPE from the GROUP BY:
select s.pmn_code, s.ref_period,
min(s.SERVICE_TYPE) as service_type,
min(s.status) keep (dense_rank last order by s.updated_dtm) as status,
max(s.updated_dtm) as updated_dtm
from tempChkStatus s
group by s.pmn_code, s.ref_period;
The GROUP BY expressions define the rows returns by an aggregation query.
This version uses MIN() on SERVICE_TYPE. It is not clear what logic you want for the result set.

Oracle 11g - SQL to Calculate time difference between several rows

PROBLEM
I'm still finding my feet with SQL and trying to calculate how long a certain user has been scanning items during their shift.
Each scan is timestamped generating a unique 9 digit sequence number (SEQ column) and date/time in the format 05-NOV-16 15:35:24 (THE_DATE column).
The person may be scanning for several hours, and what im trying to do is subtract the first timestamp they generated from the very last timestamp at the end of their shift.
So for example given this data sample:
+-----------+--------------------+--------+---------+---------+------------+-----------+
| SEQ | THE_DATE | SCANID | LOCATN | USER_ID | FIRST_NAME | LAST_NAME |
+-----------+--------------------+--------+---------+---------+------------+-----------+
| 103939758 | 05-NOV-16 14:36:22 | 194972 | DOOR 19 | AX9868 | Mike | Derry |
| 103939780 | 05-NOV-16 14:38:07 | 194972 | DOOR 19 | AX9868 | Mike | Derry |
| 103939792 | 05-NOV-16 14:39:24 | 194972 | DOOR 19 | AX9868 | Mike | Derry |
| 103940184 | 05-NOV-16 15:16:53 | 194972 | DOOR 19 | AX9868 | Mike | Derry |
| 103940185 | 05-NOV-16 15:51:41 | 194972 | DOOR 19 | AX9868 | Mike | Derry |
| 103940214 | 05-NOV-16 09:51:42 | 194993 | DOOR 16 | BC1910 | Tony | McCann |
| 103940215 | 05-NOV-16 15:19:06 | 194993 | DOOR 16 | BC1910 | Tony | McCann |
|+-----------+--------------------+--------+---------+---------+------------------------
DESIRED RESULT
I would like to subtract the timestamp in the first row for Mike Derry, from the last row on which he appears, row 5 in this case, so that i have an answer in hours (1.25).
the final result should be grouped by day and by user_id,first_name and last_name.
So far i have looked online and at the oracle documentation ,which led me to try using the LEAD function which seemed promising. It looks at the next rows to find the next timestamp where a userid appears next and then partitions by this userid to create a new column with that timestamp.
So the SQL looked like this
SELECT SEQ, THE_DATE,SCANID,LOCATN,USER_ID,LEAD(SYSDAT ) OVER (PARTITION BY USER_ID ORDER BY SYSDAT) AS NEXT_SCAN
FROM myTable...
However this is giving me incorrect results as it seems to double count the time difference. Im sure you SQL gurus have a more elegant way around this as i dont think this function suits this particular problem :)
So the final result im trying to achieve is:
+-----------+---------+------------+-----------+-----------+
| THE_DATE | USER_ID | FIRST_NAME | LAST_NAME | TOTAL_HRS |
+-----------+---------+------------+-----------+-----------+
| 05-NOV-16 | AX9868 | Mike | Derry | 1.25 |
| 05-NOV-16 | BC1910 | Tony | McCann | 5.47 |
+-----------+---------+------------+-----------+-----------+
Your help is much appreciated
Notes.... you shouldn't have redundant data (first name, last name) in this table, you should have a separate table just for that. It seems your hours are truncated and not rounded? (the rounding would give 1.26 in the first row).
with
test_data ( seq, the_date, scanid, locatn, user_id, first_name, last_name ) as (
select 103939758, to_date('05-NOV-16 14:36:22', 'dd-MON-yy hh24:mi:ss'), 194972, 'DOOR 19', 'AX9868', 'Mike', 'Derry' from dual union all
select 103939780, to_date('05-NOV-16 14:38:07', 'dd-MON-yy hh24:mi:ss'), 194972, 'DOOR 19', 'AX9868', 'Mike', 'Derry' from dual union all
select 103939792, to_date('05-NOV-16 14:39:24', 'dd-MON-yy hh24:mi:ss'), 194972, 'DOOR 19', 'AX9868', 'Mike', 'Derry' from dual union all
select 103940184, to_date('05-NOV-16 15:16:53', 'dd-MON-yy hh24:mi:ss'), 194972, 'DOOR 19', 'AX9868', 'Mike', 'Derry' from dual union all
select 103940185, to_date('05-NOV-16 15:51:41', 'dd-MON-yy hh24:mi:ss'), 194972, 'DOOR 19', 'AX9868', 'Mike', 'Derry' from dual union all
select 103940214, to_date('05-NOV-16 09:51:42', 'dd-MON-yy hh24:mi:ss'), 194993, 'DOOR 16', 'BC1910', 'Tony', 'McCann' from dual union all
select 103940215, to_date('05-NOV-16 15:19:06', 'dd-MON-yy hh24:mi:ss'), 194993, 'DOOR 16', 'BC1910', 'Tony', 'McCann' from dual
)
-- end of test data; solution (SQL query) begins below this line
select trunc(the_date) as the_date, user_id, first_name, last_name,
trunc(24 * (max(the_date) - min(the_date)), 2) as total_hrs
from test_data
group by trunc(the_date), user_id, first_name, last_name
;
THE_DATE USER_ID FIRST_NAME LAST_NAME TOTAL_HRS
--------- ------- ---------- --------- ----------
05-NOV-16 AX9868 Mike Derry 1.25
05-NOV-16 BC1910 Tony McCann 5.45
SELECT TRUNC(THE_DATE) as THE_DATE, USER_ID, FIRST_NAME, LAST_NAME,
MAX(THE_DATE) - MIN(THE_DATE) as TOTAL_HRS
FROM yourTable
GROUP BY TRUNC(THE_DATE), USER_ID, FIRST_NAME, LAST_NAME

Oracle SQL - Listagg with Rtrim and Regexp - Duplicates still present

I am using LISTAGG with RTRIM and REGEXP_REPLACE to create a comma delimited list of Test Scores but remove duplicates.
The problem is that there are still duplicates.
The data given below is directly from the SORTEST table. (SELECT * FROM SORTEST WHERE SORTEST_PIDM = '260670') I did eliminate the columns I am not using.
Q1: Why are there duplicates?
Q2: How can they be eliminated?
I think it may have to do with there being two sets of A01-A05 scores. It only happens on persons with more than one set of A scores. This does not make sense to me though since I am looking for scores LIKE 'A%B'
CODE:
SELECT DISTINCT
SP.SPRIDEN_ID AS "STUDENT_ID",
t2.sortest_pidm,
SP.SPRIDEN_LAST_NAME AS "LAST",
SP.SPRIDEN_FIRST_NAME AS "FIRST",
RTRIM(
REGEXP_REPLACE(
(
listagg ((T2.SORTEST_TESC_CODE || '-' || T2.SORTEST_TEST_SCORE), ', ')
WITHIN GROUP (ORDER BY SP.SPRIDEN_ID)
OVER (PARTITION BY SP.SPRIDEN_ID)),
'([^-]*)(-\1)+($|-)',
'\1\3'),
'-') TEST
FROM
SPRIDEN SP
left outer join SPBPERS B on SP.spriden_pidm = b.spbpers_pidm
JOIN SORTEST T2 ON T2.SORTEST_PIDM = SP.SPRIDEN_PIDM
WHERE
SP.SPRIDEN_CHANGE_IND IS NULL
AND B.SPBPERS_DEAD_IND IS NULL
AND B.SPBPERS_CONFID_IND <> 'Y'
AND T2.SORTEST_TADM_CODE IS NULL
AND
T2.SORTEST_TESC_CODE IN ('CM1B', 'CM2B', 'CR1B', 'CW1B', 'A01B', 'A02B', 'A03B', 'A04B',
'A05B', 'S01B', 'S02B', 'S95B', 'DSPW', 'DSPR', 'DSPM')
AND sP.spriden_change_ind is null
AND SP.SPRIDEN_ID IN ( 'A00154876')
Data
Please note that SORTEST_PIDM = SPRIDEN_PIDM. I did not include the SPRIDEN ID or name because I wanted to simplify the data section.
+--------------+-------------------+-------------------+--------------------+
| SORTEST_PIDM | SORTEST_TESC_CODE | SORTEST_TEST_DATE | SORTEST_TEST_SCORE |
+--------------+-------------------+-------------------+--------------------+
| | | | |
| 260670 | A01 | 1-Mar-12 | 20 |
| 260670 | A01 | 1-Oct-12 | 22 |
| 260670 | A01B | 9-Jan-13 | 22 |
| 260670 | A02 | 1-Mar-12 | 19 |
| 260670 | A02 | 1-Oct-12 | 19 |
| 260670 | A02B | 5-Jun-12 | 19 |
| 260670 | A03 | 1-Mar-12 | 21 |
| 260670 | A03 | 1-Oct-12 | 19 |
| 260670 | A03B | 5-Jun-12 | 21 |
| 260670 | A04 | 1-Mar-12 | 23 |
| 260670 | A04 | 1-Oct-12 | 22 |
| 260670 | A04B | 5-Jun-12 | 23 |
| 260670 | A05 | 1-Mar-12 | 21 |
| 260670 | A05 | 1-Oct-12 | 21 |
| 260670 | A05B | 5-Jun-12 | 21 |
| 260670 | DSPM | 5-Jun-12 | 4 |
| 260670 | DSPR | 5-Jun-12 | 4 |
| 260670 | DSPW | 5-Jun-12 | 4 |
+--------------+-------------------+-------------------+--------------------+
Results:
+------------+--------------+--------+--------+------------------------------------------------+
| STUDENT_ID | SORTEST_PIDM | LAST | FIRST | TEST |
+------------+--------------+--------+--------+------------------------------------------------+
| A00154876 | 260670 | Fowler | Martin | A01B-22, A02B-19, A03B-21, A04B-23, A05B-21, |
| | | | | DSPM-4, DSPR-4, DSPW-4, |
| | | | | A01B-22, A02B-19, A03B-21, A04B-23, A05B-21, |
| | | | | DSPM-4, DSPR-4, DSPW-4 |
+------------+--------------+--------+--------+------------------------------------------------+
These are my Desired Results:
+------------+--------------+--------+--------+--------------------------------------------+
| STUDENT_ID | SORTEST_PIDM | LAST | FIRST | TEST |
+------------+--------------+--------+--------+--------------------------------------------+
| A00249466 | 260670 | Fowler | Martin | A01B-22, A02B-19, A03B-21,A04B-23, A05B-21,|
| | | | | DSPM-4, DSPR-4, DSPW-4 |
+------------+--------------+--------+--------+--------------------------------------------+
Oracle Setup:
CREATE TABLE SPRIDEN( SPRIDEN_ID, SPRIDEN_PIDM, SPRIDEN_LAST_NAME, SPRIDEN_FIRST_NAME ) AS
SELECT 'A00154876', 260670, 'Fowler', 'Martin' FROM DUAL;
CREATE TABLE SORTEST ( SORTEST_PIDM, SORTEST_TESC_CODE, SORTEST_TEST_DATE, SORTEST_TEST_SCORE ) AS
SELECT 260670, 'A01', DATE '2012-03-1', 20 FROM DUAL UNION ALL
SELECT 260670, 'A01', DATE '2012-10-1', 22 FROM DUAL UNION ALL
SELECT 260670, 'A01B', DATE '2013-01-9', 22 FROM DUAL UNION ALL
SELECT 260670, 'A02', DATE '2012-03-1', 19 FROM DUAL UNION ALL
SELECT 260670, 'A02', DATE '2012-10-1', 19 FROM DUAL UNION ALL
SELECT 260670, 'A02B', DATE '2012-06-5', 19 FROM DUAL UNION ALL
SELECT 260670, 'A03', DATE '2012-03-1', 21 FROM DUAL UNION ALL
SELECT 260670, 'A03', DATE '2012-10-1', 19 FROM DUAL UNION ALL
SELECT 260670, 'A03B', DATE '2012-06-5', 21 FROM DUAL UNION ALL
SELECT 260670, 'A04', DATE '2012-03-1', 23 FROM DUAL UNION ALL
SELECT 260670, 'A04', DATE '2012-10-1', 22 FROM DUAL UNION ALL
SELECT 260670, 'A04B', DATE '2012-06-5', 23 FROM DUAL UNION ALL
SELECT 260670, 'A05', DATE '2012-03-1', 21 FROM DUAL UNION ALL
SELECT 260670, 'A05', DATE '2012-10-1', 21 FROM DUAL UNION ALL
SELECT 260670, 'A05B', DATE '2012-06-5', 21 FROM DUAL UNION ALL
SELECT 260670, 'DSPM', DATE '2012-06-5', 4 FROM DUAL UNION ALL
SELECT 260670, 'DSPR', DATE '2012-06-5', 4 FROM DUAL UNION ALL
SELECT 260670, 'DSPW', DATE '2012-06-5', 4 FROM DUAL;
Query:
SELECT DISTINCT
SP.SPRIDEN_ID AS "STUDENT_ID",
t2.sortest_pidm,
SP.SPRIDEN_LAST_NAME AS "LAST",
SP.SPRIDEN_FIRST_NAME AS "FIRST",
listagg ( T2.SORTEST_TESC_CODE || '-' || T2.SORTEST_TEST_SCORE, ', ')
WITHIN GROUP (ORDER BY T2.SORTEST_TESC_CODE, T2.SORTEST_TEST_SCORE)
OVER (PARTITION BY SP.SPRIDEN_ID) AS TEST
FROM SPRIDEN SP
JOIN ( SELECT DISTINCT
SORTEST_PIDM,
SORTEST_TESC_CODE,
SORTEST_TEST_SCORE
FROM SORTEST
WHERE SORTEST_TESC_CODE IN ('CM1B', 'CM2B', 'CR1B', 'CW1B', 'A01B', 'A02B', 'A03B', 'A04B', 'A05B', 'S01B', 'S02B', 'S95B', 'DSPW', 'DSPR', 'DSPM') ) T2
ON T2.SORTEST_PIDM = SP.SPRIDEN_PIDM;
Results:
STUDENT_ID SORTEST_PIDM LAST FIRST TEST
---------- ------------ ------ ------ --------------------------------------------------------------------
A00154876 260670 Fowler Martin A01B-22, A02B-19, A03B-21, A04B-23, A05B-21, DSPM-4, DSPR-4, DSPW-4