Solved

splitting string - oracle sql syntax

Posted on 2014-08-01
8
291 Views
Last Modified: 2014-08-09
please see the attached spreadheet which shows

fig 1.  current output from tbl_marks (select * from tbl_marks where stud_id = 222648)
this table records student attendance over the academic year. both morning (AM) and afternoon (PM) marks are recorded (so there are two characters for each day). there are around 730 characters in each mark string (365 days * 2)

fig2. desired output 1
each students daily attendance on one row (AM mark and PM mark).

fig2. desired output 2
each students morning and afternoon attendance on a separate row .

any help to write both queries is appreciated.
ee-example.xlsx
0
Comment
Question by:tonMachine100
  • 3
  • 2
  • 2
  • +1
8 Comments
 
LVL 48

Expert Comment

by:PortletPaul
ID: 40233784
What a  nicely prepared and utterly clear question! Thank you.

Could I ask for some "raw data" from [TBL_MARKS] please (not an image)
0
 
LVL 142

Expert Comment

by:Guy Hengel [angelIII / a3]
ID: 40233836
please check out this page to split your string (marks) into rows:
http://www.oracle-developer.net/display.php?id=412
0
 

Author Comment

by:tonMachine100
ID: 40234324
Guy - thanks for the link, i'll check it out.

PortletPaul - heres an updated version of the attachment - this time with raw data.
ee-example-with-data.xlsx
0
PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

 
LVL 73

Expert Comment

by:sdstuber
ID: 40234330
I made the assumption from your example that the desired output  was not correct for 309518.

The other two IDs have date sequences that begin on their start_date.  That one does not.

Also I went up to 366 and 732 to support the extra day in leap years


SELECT id,
       stud_id,
       attendance_date,
       am_mark,
       pm_mark
  FROM (SELECT n,
               id,
               stud_id,
               start_date + n - 1 attendance_date,
               SUBSTR(marks, n * 2 - 1, 1) am_mark,
               SUBSTR(marks, n * 2, 1) pm_mark,
               marks
          FROM tbl_marks,
               (    SELECT LEVEL n
                      FROM DUAL
                CONNECT BY LEVEL <= 366))
 WHERE n * 2 <= LENGTH(marks);

Open in new window


SELECT id,
       stud_id,
       attendance_date,
       am_pm,
       mark
  FROM (SELECT n,
               id,
               stud_id,
               start_date + n - 1 attendance_date,
               CASE WHEN MOD(n, 2) = 1 THEN 'am' ELSE 'pm' END am_pm,
               SUBSTR(marks, n, 1) mark,
               marks
          FROM tbl_marks,
               (    SELECT LEVEL n
                      FROM DUAL
                CONNECT BY LEVEL <= 732))
 WHERE n <= LENGTH(marks);

Open in new window

0
 
LVL 48

Expert Comment

by:PortletPaul
ID: 40238252
No points please.
Thanks for the actual values. Either query by sdstuber above will work

The marking system produces these combinations:
| AM_MARK | PM_MARK | OCCURS |
|---------|---------|--------|
|       # |       # |    518 |
|       / |       \ |    489 |
|       L |       \ |      8 |
|       M |       M |      5 |
|       / |       B |      1 |
|       / |       V |      1 |
|       H |       H |      9 |
|       M |       I |      1 |
|       / |       I |      1 |
|       X |       X |      6 |
|       C |       C |      1 |
|       Y |       Y |      1 |
|       I |       I |     50 |

http://sqlfiddle.com/#!4/fec06/9

Open in new window

0
 

Author Comment

by:tonMachine100
ID: 40238459
thanks guys, but i've found an issue.

I've run the second query (where ID = 309518):

SELECT id,
       stud_id,
       attendance_date,
       am_pm,
       mark
  FROM (SELECT n,
               id,
               stud_id,
               start_date + n - 1 attendance_date,
               CASE WHEN MOD(n, 2) = 1 THEN 'am' ELSE 'pm' END am_pm,
               SUBSTR(marks, n, 1) mark,
               marks
          FROM tbl_marks,
               (    SELECT LEVEL n
                      FROM DUAL
                CONNECT BY LEVEL <= 732)
       
       where
        ID = 309518
       
       )
 WHERE n <= LENGTH(marks);

Open in new window

This is the output:
|     ID | STUD_ID |                  ATTENDANCE_DATE | AM_PM | MARK |
|--------|---------|----------------------------------|-------|------|
| 309518 |  222648 | September, 04 2006 00:00:00+0000 |    am |    X |
| 309518 |  222648 | September, 05 2006 00:00:00+0000 |    pm |    X |
| 309518 |  222648 | September, 06 2006 00:00:00+0000 |    am |    / |
| 309518 |  222648 | September, 07 2006 00:00:00+0000 |    pm |    \ |
| 309518 |  222648 | September, 08 2006 00:00:00+0000 |    am |    / |
| 309518 |  222648 | September, 09 2006 00:00:00+0000 |    pm |    \ |
| 309518 |  222648 | September, 10 2006 00:00:00+0000 |    am |    / |

Open in new window



You'll notice the incorrect date is appearing against the mark. each date should appear twice (for both its AM and PM mark). The code is outputting the date just once.

thanks
0
 
LVL 73

Accepted Solution

by:
sdstuber earned 500 total points
ID: 40238833
oops sorry about that, forgot to include the division


SELECT id,
       stud_id,
       attendance_date,
       am_pm,
       mark,
       marks
  FROM (SELECT n,
               id,
               stud_id,
               start_date + FLOOR((n - 1) / 2) attendance_date,   --- this line is what I changed
               CASE WHEN MOD(n, 2) = 1 THEN 'am' ELSE 'pm' END am_pm,
               SUBSTR(marks, n, 1) mark,
               marks
          FROM tbl_marks,
               (    SELECT LEVEL n
                      FROM DUAL
                CONNECT BY LEVEL <= 732))
 WHERE n <= LENGTH(marks);
0
 

Author Closing Comment

by:tonMachine100
ID: 40250372
Thanks. You've all been a great help
0

Featured Post

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Using MERGE to UPDATE a third table 14 37
Mysql Left Join Case 10 55
Oracle collections 15 23
Correct an issue with a where clause with calculation 2 31
If you find yourself in this situation “I have used SELECT DISTINCT but I’m getting duplicates” then I'm sorry to say you are using the wrong SQL technique as it only does one thing which is: produces whole rows that are unique. If the results you a…
Occasionally there is a need to clean table columns, especially if you have inherited legacy data. There are obviously many ways to accomplish that, including elaborate UPDATE queries with anywhere from one to numerous REPLACE functions (even within…
This video explains at a high level with the mandatory Oracle Memory processes are as well as touching on some of the more common optional ones.
Via a live example show how to connect to RMAN, make basic configuration settings changes and then take a backup of a demo database

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question