The sky arrives as files. Six lessons that load 9,096 stars, 88 constellations, the 743 lines that draw them and the 27 nakshatra junction stars, with Data Load Definitions you can run again whenever the files change. You finish with a full catalog and an admin page that loads it.
How Part 2 works
Turnout's users typed their data in. SkySutra's catalog comes from astronomers, as files, in astronomers' units: right ascension in hours, minutes and seconds, declination in degrees, minutes and seconds, star names with Greek letters. A Data Load Definition is APEX's way to say, once, how a file becomes rows: which column goes where, what to convert on the way in, what to look up, and what to do with a bad row.
| Lesson | You build | New |
|---|---|---|
| 2.1 Choosing a catalog | Nothing yet: you look at the files | |
| 2.2 Data Load Definitions | The Constellations definition, and the start of Stars | New: Data Load Definitions |
| 2.3 Transformations on the way in | Stars' conversions and the constellation lookup | New: SQL Expression and Lookup columns, transformations |
| 2.4 Constellations | The Constellation Lines definition, with three lookups and an error table | New: error logging |
| 2.5 The 27 nakshatras | The Nakshatra Stars definition, which fills in one column of existing rows | |
| 2.6 Loads you can run again | The Load the Catalog page, for administrators only | New: Data Loading page |
Load order matters, and it's the order of the lessons: stars look up their constellation, lines look up their stars, nakshatras look up their junction star. A lookup can only find what's already loaded.
Before you start
You need Part 1 done: the 22 tables, the seed data, and sign-in working. Download this part's four files:
| File | Rows | What's in it |
|---|---|---|
constellations.csv |
88 | Abbreviation, name, Vedic name |
bright_stars.csv |
9,096 | The star catalog, in its own units (Lesson 2.1) |
constellation_lines.csv |
743 | Each stick-figure line, as two HR numbers |
nakshatra_stars.csv |
27 | Each nakshatra's junction star, by HR number |
Lesson 2.1 — Choosing a catalog
Outcome: know what's in SkySutra's star file, where it came from, and why it stops at the stars you can see.
The question. There are catalogs with a billion stars. Why does SkySutra load 9,096?
The decision. Load the stars a person can see without a telescope, and nothing more.
The file is the Yale Bright Star Catalogue, 5th revised edition (Hoffleit and Warren, 1991): every star brighter than about magnitude 6.5, the limit of the eye on a dark night. It numbers 9,110 entries; 14 of them turned out not to be single stars (novae, a few clusters and galaxies) and have no position, so the file has 9,096 rows. Its numbers are the HR numbers from Lesson 1.1.
| Reason | Why it matters here |
|---|---|
| It's the sky the app talks about | SkySutra says "look up and find this"; a star you can't see is noise |
| It's small | About 0.7 MB as a file and a few MB in the table. The free apex.oracle.com workspace has a storage limit, and a big catalog would use it up |
| It's free to use | Distributed for research and education; credit it wherever the data shows (the app's About page). The constellation figures come from d3-celestial (BSD licence) |
| Everything references it | Star atlases, the constellation-line data and the nakshatra tables all use HR numbers |
Open bright_stars.csv in a text editor and look at Aldebaran's row:
1457,Aldebaran,α Tauri,Tau,04h 35m 55.2s,+16° 30′ 33″,+0.063,-0.190,0.85,+1.54,K5+III,Rohini
None of it is in the shape SS_STARS wants. Right ascension is in hours, not degrees. Declination is degrees, minutes and seconds. Proper motion (how fast the star drifts across the sky over centuries) is in arcseconds a year; the table holds milliarcseconds. The constellation is Tau, the table wants an id. Lessons 2.2 and 2.3 handle each one.
Check yourselfWhy not load a catalog of a million stars?
SkySutra is about the naked-eye sky, and the free workspace doesn't have the room.
Lesson 2.2 — Data Load Definitions
Outcome: create a Data Load Definition from a sample file, and know what each of its settings decides.
The question. We could write a PL/SQL procedure to read each file. What does a Data Load Definition give us instead?
The decision. Describe each file once, as a shared component; let APEX do the reading, converting and error handling; reuse the definition from a page, from PL/SQL (apex_data_loading.load_data) or both.
A definition has two halves:
| Half | It decides | Example |
|---|---|---|
| Data Load | Which table, and how rows go in: Append, Merge or Replace; what to do on an error | Stars merge into SS_STARS |
| Data Profile | How to read the file: format, encoding, and one column per value | RA is text from the file; RA_DEG is computed from it |
A profile column whose name matches a table column is loaded into it. A column whose name doesn't match (like RA) is still read, and other columns can use it, but it isn't loaded anywhere.
1. Constellations
- Shared Components › Data Load Definitions › Create. Keep From scratch, Next.
- Name
Constellations, Table NameSS_CONSTELLATIONS. Next. - Upload a File: drop in
constellations.csv. Next. - On Map Columns, change File Encoding to Unicode UTF-8. The default is Western European ISO-8859-1, which would turn the ö in Boötes into two wrong characters.
- The three columns map themselves: the file's headers match the table's columns. Tick Primary Key on the
ABBRrow. That makes this a Merge on the abbreviation: run it again and existing constellations are updated, not duplicated. - Look at Preview, then click Create Data Load (not "Create and Add Page": the page comes in Lesson 2.6, for all four files at once).
2. Stars, first pass
- Create again: Name
Stars, Table NameSS_STARS, sample filebright_stars.csv, File Encoding Unicode UTF-8. - Only
BAYER,B_VandVEDIC_NAMEmap themselves; the others have different names in the file (hr,vmag,ra). Click Create Data Load anyway: the wizard keeps only mapped columns, and you'll add the rest properly in Lesson 2.3. - Open Stars. Set Loading Method to Merge later, once it has a primary key (Lesson 2.3). Set When on Error to Log Error into Collection, Collection Name
STAR_LOAD_ERRORS. Apply Changes.
Why not Log into Error Log for stars? APEX refuses: "Log into Error Log not supported for Merge loading method nor Append loading method if a primary key column defined." A merging load reports its bad rows in a collection instead, and the load page shows them (Lesson 2.6).
Check yourselfWhat does ticking Primary Key on ABBR change?
The definition merges on the abbreviation, so a second load updates rows instead of adding copies.
Lesson 2.3 — Transformations on the way in
Outcome: turn the catalog's units into SkySutra's on the way in, without touching the file.
The question. RA arrives as 04h 35m 55.2s. Where does it become 68.98°?
The decision. In the profile, with three kinds of column: Data (read from the file, optionally tidied by a transformation), SQL Expression (computed from Data columns), and Lookup (an id found in another table).
1. Add the Data columns
Open Stars › Edit Data Profile. In the columns grid, use Add Data Column for each row below. Every column needs a Static ID (lower case with hyphens, like hr-number). Then Apply Changes.
| Name | Data Type | Selector (the file's header) | Primary Key |
|---|---|---|---|
HR_NUMBER |
Number | HR |
Yes |
PROPER_NAME |
Varchar2 | NAME |
|
CONSTELLATION |
Varchar2 | CONSTELLATION |
|
RA |
Varchar2 | RA |
|
DEC |
Varchar2 | DEC |
|
PM_RA |
Number | PM_RA |
|
PM_DEC |
Number | PM_DEC |
|
MAGNITUDE |
Number | VMAG |
|
SPECTRAL_TYPE |
Varchar2 | SPTYPE |
Now go back to Stars and set Loading Method to Merge: HR_NUMBER is the key, so a second load updates each star in place. That matters: observations and lore point at stars by id, and a merge keeps the ids.
2. Compute degrees: SQL Expression columns
Add Column, Column Type SQL Expression, Data Type Number. The expression can use any Data column by name.
| Name | SQL Expression |
|---|---|
RA_DEG |
( to_number(regexp_substr(RA, '[0-9.]+', 1, 1)) + to_number(regexp_substr(RA, '[0-9.]+', 1, 2)) / 60 + to_number(regexp_substr(RA, '[0-9.]+', 1, 3)) / 3600 ) * 15 |
DEC_DEG |
case when trim(DEC) like '-%' then -1 else 1 end * ( to_number(regexp_substr(DEC, '[0-9.]+', 1, 1)) + to_number(regexp_substr(DEC, '[0-9.]+', 1, 2)) / 60 + to_number(regexp_substr(DEC, '[0-9.]+', 1, 3)) / 3600 ) |
PM_RA_MAS |
PM_RA * 1000 |
PM_DEC_MAS |
PM_DEC * 1000 |
How the RA one works: regexp_substr(RA, '[0-9.]+', 1, n) picks the nth run of digits from 04h 35m 55.2s: 04, 35, 55.2. Hours plus minutes/60 plus seconds/3600 gives 4.5987 hours; times 15 (360° in 24 hours) gives 68.98°. Declination works the same way in degrees, with the sign taken from the front: -00° 30′ 11″ is negative even though its degrees are 0, which is why the sign is read from the text and not from the number.
3. Find the constellation: a Lookup column
The file says Tau; the table wants SS_CONSTELLATIONS.ID, and abbreviations are stored in capitals (TAU).
- Edit the
CONSTELLATIONcolumn. Set Transformation to To Upper Case. Apply Changes. - Add Column: Name
CONSTELLATION_ID, Column Type Lookup, Data Type Number, TableSS_CONSTELLATIONS, Return ColumnID, Table Column 1ABBR, Data Column 1CONSTELLATION.
A lookup that finds nothing returns null. constellation_id allows nulls, so a misspelled abbreviation would load a star with no constellation; the check at the end of this part counts them.
Check yourselfWhy is RA a Data column when SS_STARS has no RA column?
So RA_DEG can be computed from it; a profile column with no matching table column is read but not loaded.
Lesson 2.4 — Constellations
Outcome: load the 743 lines that draw the constellations, and catch any line whose stars aren't in the catalog.
The question. A line is "from HR 1457 to HR 1409". The table wants two star ids. What if a number isn't in the catalog?
The decision. Three lookups per row, Replace as the loading method, and bad rows to an error log table.
1. Make the error table
In SQL Commands:
begin
dbms_errlog.create_error_log('SS_CONSTELLATION_LINES');
end;
That creates ERR$_SS_CONSTELLATION_LINES: the same columns as the table, as text, plus ORA_ERR_MESG$ for the reason a row failed.
2. The definition
- Create: Name
Constellation Lines, Table NameSS_CONSTELLATION_LINES, sample fileconstellation_lines.csv, UTF-8. OnlySEQmaps itself. Create Data Load. - Edit Data Profile, Add Data Column three times:
CONSTELLATION(Varchar2, selectorCONSTELLATION),FROM_HR(Number,FROM_HR),TO_HR(Number,TO_HR). Apply Changes. - Add Column three times, each a Lookup returning
ID:
| Name | Table | Table Column 1 | Data Column 1 |
|---|---|---|---|
CONSTELLATION_ID |
SS_CONSTELLATIONS |
ABBR |
CONSTELLATION |
FROM_STAR_ID |
SS_STARS |
HR_NUMBER |
FROM_HR |
TO_STAR_ID |
SS_STARS |
HR_NUMBER |
TO_HR |
- Back on the definition: Loading Method Replace; When on Error Log into Error Log; Error Logging Table
ERR$_SS_CONSTELLATION_LINES. Apply Changes.
Why Replace here and Merge for stars
| Stars | Lines | |
|---|---|---|
| Other tables point at its rows | Yes: observations, lore, nakshatras | No |
| A row has a natural key | Yes, the HR number | No: a line is just two stars |
| So the load | Merges: updates in place, ids stay put | Replaces: deletes every row, inserts the file |
All three line columns are not null. If a lookup finds nothing, the insert fails, and the row lands in the error table with the reason, instead of stopping the load.
Check yourselfWhy can't the lines merge?
There's no natural key to match a line in the file to a row in the table; and nothing references lines, so replacing them is safe.
Lesson 2.5 — The 27 nakshatras
Outcome: point each nakshatra at its junction star, without touching anything else in the row.
The question. The 27 nakshatra rows already exist (Part 1's seed). The file only knows "Rohini, HR 1457". How does a load fill in one column?
The decision. Merge on SEQ, with only the columns the file can supply.
- Create: Name
Nakshatra Stars, Table NameSS_NAKSHATRAS, samplenakshatra_stars.csv, UTF-8.SEQmaps itself. Create Data Load. - Edit Data Profile: set Primary Key on
SEQ, and Add Data ColumnHR_NUMBER(Number, selectorHR_NUMBER). Apply Changes. - Add Column:
JUNCTION_STAR_ID, Lookup onSS_STARS, returnID,HR_NUMBER=HR_NUMBER. - Loading Method Merge. Apply Changes.
A merge updates only the columns in the profile that exist in the table: here SEQ (unchanged) and JUNCTION_STAR_ID. Names, ranges and descriptions stay as the seed left them. The file's nakshatra and star columns are there for people reading it; nothing loads them.
Check yourselfWould this load work on an empty SS_NAKSHATRAS?
No: a new row needs a name and range, which the file doesn't have; merge would try to insert and fail the not-null checks.
Lesson 2.6 — Loads you can run again
Outcome: one page, for administrators only, that loads any of the four files and shows what happened.
The question. A developer can load files in the Builder. Who loads next year's corrected catalog?
The decision. A Data Loading page in the app, behind an Administrator role.
1. The role, and a wizard default to fix
- Shared Components › Application Access Control › Add Role:
Administrator, description "Loads and maintains the star catalog." Open it again and change Static ID toADMINISTRATOR(Lesson 0.6:apex_acl.has_user_roleupper-cases what it's given). - Add User Role Assignment: your own account, Administrator.
- Shared Components › Authorization Schemes, open Administration Rights. The Create App wizard made it, and look at it: PL/SQL Function Returning Boolean,
return true;. Every signed-in person passes. Change Scheme Type to Is In Role or Group, Type Application Role, Name(s)Administrator; Error Message "Only administrators can open this page." Apply Changes.
2. The page
- Create Page › Data Loading. Page Number 20, Name
Load the Catalog, Data Load Stars, Upload Data From File. Turn off the breadcrumb and the navigation entry. Create Page. - The wizard builds a whole page: a file drop zone (
P20_FILE), a Preview of the first rows, a Load Data button, an Errors report on theSTAR_LOAD_ERRORScollection, and two processes: Load Data (the Data Loading process) and Clear Cache. - In Page Designer, page 20: Security › Authorization Scheme Administration Rights; Page Alias
LOAD.
3. One page, four files
- Add a Select List
P20_LOADto the Data Source region, before the file: Label "Catalog file", Value Required on, Static Values:
| Display | Return |
|---|---|
| 1. Constellations | constellations |
| 2. Stars | stars |
| 3. Constellation lines | constellation-lines |
| 4. Nakshatra junction stars | nakshatra-stars |
The return values are the definitions' Static IDs.
2. Preview region: in its SQL, change p_static_id => 'stars' to p_static_id => :P20_LOAD, so the preview reads the file with the right profile.
3. Rename the process Load Data to Load stars, with Server-side Condition "Item = Value", P20_LOAD = stars.
4. Add three more Data Loading processes, the same but with Data Load Definition Constellations, Constellation Lines and Nakshatra Stars, File P20_FILE, When Button Pressed Load Data, and the matching condition value. Keep Clear Cache after them.
5. A classic report In the Catalog, to see the result:
select 'Constellations' as what, (select count(*) from ss_constellations) as loaded, 88 as expected from dual union all
select 'Stars', (select count(*) from ss_stars), 9096 from dual union all
select 'Constellation lines', (select count(*) from ss_constellation_lines), 743 from dual union all
select 'Nakshatras with a junction star', (select count(junction_star_id) from ss_nakshatras), 27 from dual
4. Load, in order
Run the app, open load (page 20), and for each file in turn: pick it, drop the file, check the preview, Load Data. Each load reports "Data loading finished: n rows processed with e errors."
| Method | What a second run does | SkySutra uses it for |
|---|---|---|
| Append | Adds every row again: duplicates, or unique-key errors | Nothing |
| Merge | Updates matching rows, inserts new ones | Constellations, stars, nakshatras |
| Replace | Deletes every row, then inserts the file | Constellation lines |
Check yourselfWhy does the page check a role instead of just "signed in"?
Anyone can sign in with Google; replacing the catalog is an administrator's job. And the wizard's own scheme said return true.
Checkpoint
The catalog is in. Part 3 computes where each of those 9,096 stars is in your sky tonight.
Test it
- "In the Catalog" shows 88, 9,096, 743 and 27.
- Every star found its constellation, and no line failed:
select (select count(*) from ss_stars where constellation_id is null) as stars_without_constellation,
(select count(*) from err$_ss_constellation_lines) as failed_lines
from dual;
Both are 0. 3. Aldebaran came through the conversions:
select hr_number, proper_name, bayer, ra_deg, dec_deg, pm_ra_mas, magnitude
from ss_stars where hr_number = 1457;
RA 68.98, Dec 16.509167, proper motion 63, magnitude 0.85, Bayer α Tauri. (Lesson 0.3 used these numbers.) 4. The junction stars:
select n.seq, n.name, s.proper_name, s.bayer, s.magnitude
from ss_nakshatras n join ss_stars s on s.id = n.junction_star_id
order by n.seq;
27 rows: Ashwini is Sheratan (β Arietis), Rohini is Aldebaran. 5. Load Stars a second time. It finishes with no errors and the count stays at 9,096: a merge, not a copy.
What we found building it
- Bytes and characters. The first star load reported 20 errors:
ORA-12899: value too large for column "SS_STARS"."BAYER" (actual: 22, maximum: 20). Names like "β Trianguli Australis" are 21 characters but 22 bytes, because a Greek letter takes two bytes in UTF-8. The schema now counts characters (alter session set nls_length_semantics = charat the top ofskysutra_schema.sql, Lesson 1.8), andbayeris 30 long. If you built the tables before that fix:alter table ss_stars modify bayer varchar2(30 char);, and set the Stars profile'sBAYERcolumn Max Length to 30. - Space. On the free apex.oracle.com tier, a load can fail with an error about space or quota. To see what's using it, run
select segment_name, round(sum(bytes)/1024/1024, 1) as mb from user_segments group by segment_name order by 2 descin SQL Commands, or open Administration › Manage Service › Request Storage › Detailed Tablespace Utilization Report. Drop sample tables and apps you no longer need, then runpurge recyclebin;(dropped tables still count until you do), or ask for more under Manage Service › Request Storage.
Files
| File | Used in |
|---|---|
constellations.csv |
2.2 |
bright_stars.csv |
2.2, 2.3 |
constellation_lines.csv |
2.4 |
nakshatra_stars.csv |
2.5 |
Exercises
- Add a line to a copy of
constellation_lines.csvwith an HR number that doesn't exist (TAU,99999,1457,99). Load it, then readora_err_mesg$inERR$_SS_CONSTELLATION_LINES. Load the real file again to put things right. - Use a Regular Expression Replace transformation to load
PROPER_NAMEwith surrounding spaces removed, then explain whyTrimdoes the same job more simply. - Run the Stars definition from PL/SQL instead of the page: look up
apex_data_loading.load_dataand write the call (it needs a file as a BLOB or CLOB, and an APEX session). - Stretch: count the stars in each constellation, and find which one has the most stars brighter than magnitude 4.
Review questions
Try each one before you open it. The graded quiz is at the end of the page.
1Why does SkySutra load about 9,000 stars and not a million?
It's about the naked-eye sky, and the free workspace has limited space
2What two halves make a Data Load Definition?
The data load: target and method; the data profile: how to read each column
3Why change the file encoding to UTF-8?
The default, ISO-8859-1, would garble ö, Greek letters and the degree signs
4What happens to a profile column whose name isn't a table column?
It's read and can be used by other columns, but not loaded
5How does 04h 35m 55.2s become 68.98?
Hours + minutes/60 + seconds/3600, times 15
6What does a Lookup column return when nothing matches?
Null
7Why do stars merge but lines replace?
Other tables point at stars by id, and stars have a natural key; nothing points at lines and they have no natural key
8Why can't the star load use an error log table?
APEX doesn't support Log into Error Log with Merge; it logs to a collection instead
9What was wrong with the wizard's Administration Rights scheme?
It was return true;, so everyone passed
10Why did "β Trianguli Australis" fail in a VARCHAR2(20)?
It's 21 characters, and with byte semantics the Greek letter takes two bytes, 22 in all
Downloads for Part 2
Everything this part uses. The SQL files are plain text: open one in any editor before you run it.
- Part 2 kitskysutra-part-2.zipEvery file above in one zip, with a README
- Constellationsconstellations.csvLesson 2.2: 88 rows
- Starsbright_stars.csvLessons 2.2 and 2.3: 9,096 stars in the catalog's own units
- Constellation linesconstellation_lines.csvLesson 2.4: 743 lines, as pairs of HR numbers
- Nakshatra starsnakshatra_stars.csvLesson 2.5: each nakshatra's junction star
- LicensesLICENSES.mdWhere the catalog data comes from, and its terms
Part 2 quiz
5 questions. Get 4 right to pass. You can retake it as often as you like.