Motion database: Difference between revisions

From Wildsong
Jump to navigationJump to search
Brian Wilson (talk | contribs)
Brian Wilson (talk | contribs)
 
(25 intermediate revisions by the same user not shown)
Line 2: Line 2:
It's a demo database for developing concepts in PostgreSQL and [[Wavemaker]].
It's a demo database for developing concepts in PostgreSQL and [[Wavemaker]].


== Table creation SQL ==
For demos I sometimes run [[PostgreSQL on a Mac]]


createdb -U webadmin motion -W -T template_postgis
== Create the database and add extensions ==


DROP TABLE IF EXISTS vehicle;
export PGDATA=localhost
CREATE TABLE vehicle (
createdb -U postgres motion
  tag CHAR DEFAULT 'V',
 
psql -U postgres template1
CREATE USER motion WITH PASSWORD 'secret';
GRANT ALL PRIVILEGES ON DATABASE motion TO motion;
 
psql -U motion motion
 
CREATE EXTENSION postgis;
# Add support for Large Objects
CREATE EXTENSION lo;
 
# Show installed extensions
SELECT * FROM pg_available_extensions
WHERE comment LIKE '%string%' OR installed_version IS NOT NULL ORDER BY name;
 
# Get more info on an extension
\dx+ postgis
\dx+ lo
 
This is the SQL required to create a vehicle tracking database in PostgreSQL that can be used from [[Wavemaker]].
 
psql -U postgres
CREATE USER motion WITH PASSWORD 'QuintanaRoo';
CREATE DATABASE motion WITH owner=motion;
\c motion;
CREATE EXTENSION postgis;
# for photo support
CREATE EXTENSION lo;
 
== Tables ==
 
=== First create the look up tables ===
The vehicle table is used to describe a vehicle
 
DROP TABLE IF EXISTS vehicle;
CREATE TABLE vehicle (
   vehicle_id SERIAL NOT NULL,  
   vehicle_id SERIAL NOT NULL,  
   name VARCHAR(20) NOT NULL,
   name VARCHAR(40) NOT NULL,
   description TEXT,
   description TEXT,
   serial_number VARCHAR(40),
   serial_number VARCHAR(40),
   PRIMARY KEY(tag,vehicle_id)
   PRIMARY KEY(vehicle_id)
);
);
INSERT INTO vehicle (name,description) VALUES ('Davidson', '1995 Davidson Discovery');
INSERT INTO vehicle (name,description) VALUES ('Fuji', '1998 Fuji Touring Series');
INSERT INTO vehicle (name,description) VALUES ('Blue', '2013 Longbikes Slipstream');
INSERT INTO vehicle (name,description) VALUES ('Swallow', '1990 Specialized Stumpjumper');
INSERT INTO vehicle (name,description) VALUES ('Alba', '2010 Toyota Yaris');
INSERT INTO vehicle (name,description) VALUES ('MG', '1970 MG Midget');
INSERT INTO vehicle (name,description) VALUES ('Honda', 'Honda Civic');
SELECT * FROM vehicle;
 
The rider table describes people who can be bicyclists or car drivers/passengers.


DROP TABLE IF EXISTS photos;
DROP TABLE IF EXISTS rider;
CREATE TABLE photos (
CREATE TABLE rider (
   photo_id SERIAL NOT NULL,
   rider_id SERIAL NOT NULL,
   thumbnail BYTEA,
   name VARCHAR(10) NOT NULL,
   raster LO,
   PRIMARY KEY (rider_id)
  description TEXT,
);
  location POINT,
INSERT INTO rider (name) VALUES ('Brian');
  FOREIGN KEY(fk_photo) REFERENCES vehicle,
INSERT INTO rider (name) VALUES ('Julie');
  PRIMARY KEY(photo_id)
INSERT INTO rider (name) VALUES ('Rob');
);
SELECT * FROM rider;
CREATE TRIGGER t_raster BEFORE UPDATE OR DELETE ON photos
 
    FOR EACH ROW EXECUTE PROCEDURE lo_manage(raster);
=== Now, the trip tables ===
 
One trip can have more than one bicyclist and that means more than one rider,
or one vehicle can carry two riders on one trip,
so we need a junction table to link together riders, vehicles, and trips.
I don't care who drives if more than one person is in a car together. (Maybe they take turns.)


DROP TABLE IF EXISTS trips;
DROP TABLE IF EXISTS trip;
CREATE TABLE trips (
CREATE TABLE trip (
  tag CHAR DEFAULT 't',
   trip_id SERIAL NOT NULL,
   trip_id SERIAL NOT NULL,
   date DATESTAMP,
   date DATE,
   mileage NUMERIC,
   mileage NUMERIC,
  vehicle_id FOREIGN KEY,
  gpx_id FOREIGN KEY,
   notes TEXT,
   notes TEXT,
   PRIMARY KEY(tag,trip_id)
  gpxlog TEXT,
);
   PRIMARY KEY(trip_id)
);
INSERT INTO trip (date,mileage,notes) VALUES ('3/14/2013',15,'Airport loop');
INSERT INTO trip (date,mileage,notes) VALUES ('3/15/2013',22,'Airport loop + Walnut Ave');
INSERT INTO trip (date,mileage,notes) VALUES ('3/16/2013',14,'Bald Hill loop');
INSERT INTO trip (date,mileage,notes) VALUES ('3/18/2013',12,'HP loop');
INSERT INTO trip (date,mileage,notes) VALUES ('3/20/2013',93,'Home - Flightstats');
SELECT * FROM trip;
 
DROP TABLE IF EXISTS j_trip;
CREATE TABLE j_trip (
  j_trip_id SERIAL NOT NULL,
  trip_id INT, FOREIGN KEY (trip_id) REFERENCES trip(trip_id),
  rider_id INT, FOREIGN KEY (rider_id) REFERENCES rider(rider_id),
  vehicle_id INT, FOREIGN KEY (vehicle_id) REFERENCES vehicle(vehicle_id),
  PRIMARY KEY(j_trip_id)
);
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (1,1,1); --1 brian davidson
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (2,1,1); --2 "    "
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (2,2,4); --2 julie swallow
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (3,1,2); --3 brian fuji
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (4,1,2); --4 brian fuji
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (5,1,7); --5 brian honda
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (5,2,7); --5 julie honda
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (5,3,7); --5 rob honda
SELECT * FROM j_trip;
 
SELECT t.date,t.notes,r.name,v.name
FROM trip AS t,rider AS r,vehicle AS v, j_trip AS j
WHERE (j.trip_id=t.trip_id) AND (j.rider_id=r.rider_id) AND (j.vehicle_id=v.vehicle_id);
 
-- WRONG - shows constraint
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (5,3,8); --5 rob ???
 
=== Add tables for maintenance records ===


DROP TABLE IF EXISTS maintenance;
DROP TABLE IF EXISTS maintenance;
CREATE TABLE maintenance (
CREATE TABLE maintenance (
  tag CHAR DEFAULT 'M',
   maint_id SERIAL NOT NULL,
   maint_id SERIAL NOT NULL,
   date
   date DATE,
   description
   description TEXT,
   notes
   notes TEXT,
   vehicle_id ,
  vehicle_id INT, FOREIGN KEY(vehicle_id) REFERENCES vehicle(vehicle_id),
   PRIMARY KEY(tag,main_id)
  PRIMARY KEY(maint_id)
);
);
INSERT INTO maintenance (date, description, vehicle_id) VALUES ('2/1/2013', 'Oiled chain', 1);
INSERT INTO maintenance (date, description, notes, vehicle_id) VALUES ('3/17/2013', 'New front wheel', 'Phil Wood hub', 4);
SELECT date,name,maintenance.description FROM maintenance,vehicle WHERE maintenance.vehicle_id=vehicle.vehicle_id;
 
=== Current location for AVL ===
 
Each vehicle can have just one current location.
 
DROP TABLE IF EXISTS location;
CREATE TABLE location (
  location_id SERIAL NOT NULL,
  vehicle_id INT, FOREIGN KEY (vehicle_id) REFERENCES vehicle(vehicle_id),
   time TIMESTAMP,
  PRIMARY KEY(location_id)
);
SELECT AddGeometryColumn('location', 'geom', 4326, 'POINT', 2 );
 
\d location
                                      Table "public.location"
  Column    |        Type        |                          Modifiers                           
-------------+----------------------+----------------------------------------------------------------
location_id | integer              | not null default nextval('location_location_id_seq'::regclass)
vehicle_id  | integer              |
geom        | geometry(Point,4326) |
Indexes:
    "location_pkey" PRIMARY KEY, btree (location_id)
Foreign-key constraints:
    "location_vehicle_id_fkey" FOREIGN KEY (vehicle_id) REFERENCES vehicle(vehicle_id)
INSERT INTO location (vehicle_id, geom, time) VALUES(1, ST_GeometryFromText('POINT(0 0)',4326), NOW());
SELECT vehicle.name, time, ST_AsText(location.geom) FROM location, vehicle WHERE location.vehicle_id=vehicle.vehicle_id;
 
=== Location logs ===
 
I should do this but not today.
 
=== Dispatch log ===
 
A log of places to which vehicles have been dispatched.
Yes, I need this now! This is a little sparse but the hour is late.
 
DROP TABLE IF EXISTS dispatch_log;
CREATE TABLE dispatch_log (
  dispatch_id SERIAL NOT NULL,  PRIMARY KEY(dispatch_id),
  time TIMESTAMP,
  description VARCHAR(255)
);
 
=== Credentials ===
 
To read dispatches I need access to email on a server so I need a place to keep those settings.
 
DROP TABLE IF EXISTS account;
CREATE TABLE account (
  user_id SERIAL NOT NULL,  PRIMARY KEY(user_id),
  login VARCHAR(40),
  password VARCHAR(40),
  server VARCHAR(40)
);
 
=== Everyone needs photo tables ===
 
I don't have the lo extension installed on Kilchis so I left this table out on that installation. Maybe not everyone needs photos.
 
Using lo (Large Object) extension to hold photo in database, I like to keep everything in one place so I don't lose them.
(In the database instead of keeping them on the filesystem)
 
I could do photo/image processing in the database if I installed the PostPIC extension, see
http://drotiro.github.com/postpic/ Possibly I could use it to generate the thumbnails?
 
DROP TABLE IF EXISTS photo;
CREATE TABLE photo (
   photo_id SERIAL NOT NULL,  PRIMARY KEY(photo_id),
  time TIMESTAMP,
  thumbnail BYTEA,
  image LO,
  lat NUMERIC(8,6), lon NUMERIC(9,6),
  title VARCHAR(80),
  description TEXT
);
CREATE TRIGGER t_image BEFORE UPDATE OR DELETE ON photo
    FOR EACH ROW EXECUTE PROCEDURE lo_manage(image);
-- Lat Lon are from iTouchMap.com
INSERT INTO photo (description) VALUES ('Davidson photo');
INSERT INTO photo (description) VALUES ('Fuji photo');
INSERT INTO photo (description,lat,lon) VALUES ('Bald Hill',44.56739,-123.332099);
INSERT INTO photo (description) VALUES ('New wheel photo');
INSERT INTO photo (description,lat,lon) VALUES ('Bellfountain Rd', 44.495692, -123.337787);
INSERT INTO photo (description,lat,lon) VALUES ('MG in Gold Beach',42.564287, -124.383210);
SELECT * FROM photo;
 
Photos are good for everything -- people, rides, vehicles, maintenance... so I need a junction table to accommodate this
 
DROP TABLE IF EXISTS j_photo;
CREATE TABLE j_photo (
  j_photo_id SERIAL NOT NULL, PRIMARY KEY(j_photo_id),
  photo_id INT NOT NULL, FOREIGN KEY (photo_id) REFERENCES photo(photo_id),
  trip_id INT, FOREIGN KEY (trip_id) REFERENCES trip(trip_id),
  rider_id INT, FOREIGN KEY (rider_id) REFERENCES rider(rider_id),
  vehicle_id INT, FOREIGN KEY(vehicle_id) REFERENCES vehicle(vehicle_id),
  maint_id INT, FOREIGN KEY (maint_id) REFERENCES maintenance(maint_id)
);
INSERT INTO j_photo (photo_id,vehicle_id) VALUES (1,1);
INSERT INTO j_photo (photo_id,vehicle_id) VALUES (2,2);
INSERT INTO j_photo (photo_id,trip_id) VALUES (3,3);
INSERT INTO j_photo (photo_id,maint_id) VALUES (4,2);
INSERT INTO j_photo (photo_id,trip_id) VALUES (5,3);
INSERT INTO j_photo (photo_id,vehicle_id) VALUES (6,6);
 
SELECT p.description,v.name
FROM j_photo AS j, photo AS p, vehicle AS v
WHERE ((j.photo_id=p.photo_id) AND (j.vehicle_id=v.vehicle_id));
 
SELECT p.description,m.notes
FROM j_photo AS j, photo AS p, maintenance AS m
WHERE ((j.photo_id=p.photo_id) AND (j.maint_id=m.maint_id));
 
SELECT p.description,t.notes
FROM j_photo AS j, photo AS p, trip AS t
WHERE ((j.photo_id=p.photo_id) AND (j.trip_id=t.trip_id));
 
== Views ==
 
Views give me results that appear denormalized so that Wavemaker does not need to know about the joins.
The problem is that you can't access tables for writing if they are in views. So these are read-only.
 
-- simplest case first
CREATE VIEW maintenance_view AS
SELECT date,name,maintenance.description FROM maintenance,vehicle WHERE maintenance.vehicle_id=vehicle.vehicle_id;
 
-- more complicated version
CREATE VIEW trip_view (date, mileage, notes, rider_name, vehicle_name) AS
SELECT t.date,t.mileage,t.notes,r.name,v.name
FROM trip AS t,rider AS r,vehicle AS v, j_trip AS j
WHERE (j.trip_id=t.trip_id) AND (j.rider_id=r.rider_id) AND (j.vehicle_id=v.vehicle_id);
 
Now I can use these tables in Wavemaker * read only *
 
== Onward ==


DROP TABLE IF EXISTS gpx;
That's enough to develop the sample app so go back to [[Wavemaker]]
CREATE TABLE gpx (
  gpx_id SERIAL NOT NULL,
  upload_date DATESTAMP,
  log TEXT,
  note TEXT,
  PRIMARY KEY(gpx_id)
);


[[Category: SQL]]
[[Category: PostgreSQL]]

Latest revision as of 18:25, 30 May 2013

The Motion Database is used to keep track of my rolling stock including cars and bicycles. It's a demo database for developing concepts in PostgreSQL and Wavemaker.

For demos I sometimes run PostgreSQL on a Mac

Create the database and add extensions

export PGDATA=localhost
createdb -U postgres motion
psql -U postgres template1
CREATE USER motion WITH PASSWORD 'secret';
GRANT ALL PRIVILEGES ON DATABASE motion TO motion;
psql -U motion motion
CREATE EXTENSION postgis;

# Add support for Large Objects
CREATE EXTENSION lo;
# Show installed extensions
SELECT * FROM pg_available_extensions
WHERE comment LIKE '%string%' OR installed_version IS NOT NULL ORDER BY name;
# Get more info on an extension
\dx+ postgis
\dx+ lo

This is the SQL required to create a vehicle tracking database in PostgreSQL that can be used from Wavemaker.

psql -U postgres

CREATE USER motion WITH PASSWORD 'QuintanaRoo';
CREATE DATABASE motion WITH owner=motion;
\c motion;
CREATE EXTENSION postgis;
# for photo support
CREATE EXTENSION lo;

Tables

First create the look up tables

The vehicle table is used to describe a vehicle

DROP TABLE IF EXISTS vehicle;
CREATE TABLE vehicle (
 vehicle_id SERIAL NOT NULL, 
 name VARCHAR(40) NOT NULL,
 description TEXT,
 serial_number VARCHAR(40),
 PRIMARY KEY(vehicle_id)
);
INSERT INTO vehicle (name,description) VALUES ('Davidson', '1995 Davidson Discovery');
INSERT INTO vehicle (name,description) VALUES ('Fuji', '1998 Fuji Touring Series');
INSERT INTO vehicle (name,description) VALUES ('Blue', '2013 Longbikes Slipstream');
INSERT INTO vehicle (name,description) VALUES ('Swallow', '1990 Specialized Stumpjumper');
INSERT INTO vehicle (name,description) VALUES ('Alba', '2010 Toyota Yaris');
INSERT INTO vehicle (name,description) VALUES ('MG', '1970 MG Midget');
INSERT INTO vehicle (name,description) VALUES ('Honda', 'Honda Civic');
SELECT * FROM vehicle;

The rider table describes people who can be bicyclists or car drivers/passengers.

DROP TABLE IF EXISTS rider;
CREATE TABLE rider (
 rider_id SERIAL NOT NULL,
 name VARCHAR(10) NOT NULL,
 PRIMARY KEY (rider_id)
);
INSERT INTO rider (name) VALUES ('Brian');
INSERT INTO rider (name) VALUES ('Julie');
INSERT INTO rider (name) VALUES ('Rob');
SELECT * FROM rider;

Now, the trip tables

One trip can have more than one bicyclist and that means more than one rider, or one vehicle can carry two riders on one trip, so we need a junction table to link together riders, vehicles, and trips. I don't care who drives if more than one person is in a car together. (Maybe they take turns.)

DROP TABLE IF EXISTS trip;
CREATE TABLE trip (
 trip_id SERIAL NOT NULL,
 date DATE,
 mileage NUMERIC,
 notes TEXT,
 gpxlog TEXT,
 PRIMARY KEY(trip_id)
);
INSERT INTO trip (date,mileage,notes) VALUES ('3/14/2013',15,'Airport loop');
INSERT INTO trip (date,mileage,notes) VALUES ('3/15/2013',22,'Airport loop + Walnut Ave');
INSERT INTO trip (date,mileage,notes) VALUES ('3/16/2013',14,'Bald Hill loop');
INSERT INTO trip (date,mileage,notes) VALUES ('3/18/2013',12,'HP loop');
INSERT INTO trip (date,mileage,notes) VALUES ('3/20/2013',93,'Home - Flightstats');
SELECT * FROM trip;
DROP TABLE IF EXISTS j_trip;
CREATE TABLE j_trip (
 j_trip_id SERIAL NOT NULL,
 trip_id INT, FOREIGN KEY (trip_id) REFERENCES trip(trip_id),
 rider_id INT, FOREIGN KEY (rider_id) REFERENCES rider(rider_id),
 vehicle_id INT, FOREIGN KEY (vehicle_id) REFERENCES vehicle(vehicle_id),
 PRIMARY KEY(j_trip_id)
);
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (1,1,1); --1 brian davidson
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (2,1,1); --2 "     "
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (2,2,4); --2 julie swallow
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (3,1,2); --3 brian fuji
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (4,1,2); --4 brian fuji
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (5,1,7); --5 brian honda
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (5,2,7); --5 julie honda
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (5,3,7); --5 rob honda
SELECT * FROM j_trip;
SELECT t.date,t.notes,r.name,v.name
FROM trip AS t,rider AS r,vehicle AS v, j_trip AS j
WHERE (j.trip_id=t.trip_id) AND (j.rider_id=r.rider_id) AND (j.vehicle_id=v.vehicle_id);
-- WRONG - shows constraint
INSERT INTO j_trip (trip_id,rider_id,vehicle_id) VALUES (5,3,8); --5 rob ???

Add tables for maintenance records

DROP TABLE IF EXISTS maintenance;
CREATE TABLE maintenance (
 maint_id SERIAL NOT NULL,
 date DATE,
 description TEXT,
 notes TEXT,
 vehicle_id INT, FOREIGN KEY(vehicle_id) REFERENCES vehicle(vehicle_id),
 PRIMARY KEY(maint_id)
);
INSERT INTO maintenance (date, description, vehicle_id) VALUES ('2/1/2013', 'Oiled chain', 1);
INSERT INTO maintenance (date, description, notes, vehicle_id) VALUES ('3/17/2013', 'New front wheel', 'Phil Wood hub', 4);
SELECT date,name,maintenance.description FROM maintenance,vehicle WHERE maintenance.vehicle_id=vehicle.vehicle_id;

Current location for AVL

Each vehicle can have just one current location.
DROP TABLE IF EXISTS location;
CREATE TABLE location (
 location_id SERIAL NOT NULL,
 vehicle_id INT, FOREIGN KEY (vehicle_id) REFERENCES vehicle(vehicle_id),
 time TIMESTAMP,
 PRIMARY KEY(location_id)
);
SELECT AddGeometryColumn('location', 'geom', 4326, 'POINT', 2 );
\d location
                                      Table "public.location"
  Column    |         Type         |                           Modifiers                            
-------------+----------------------+----------------------------------------------------------------
location_id | integer              | not null default nextval('location_location_id_seq'::regclass)
vehicle_id  | integer              | 
geom        | geometry(Point,4326) | 
Indexes:
   "location_pkey" PRIMARY KEY, btree (location_id)
Foreign-key constraints:
   "location_vehicle_id_fkey" FOREIGN KEY (vehicle_id) REFERENCES vehicle(vehicle_id)

INSERT INTO location (vehicle_id, geom, time) VALUES(1, ST_GeometryFromText('POINT(0 0)',4326), NOW());

SELECT vehicle.name, time, ST_AsText(location.geom) FROM location, vehicle WHERE location.vehicle_id=vehicle.vehicle_id;

Location logs

I should do this but not today.

Dispatch log

A log of places to which vehicles have been dispatched. Yes, I need this now! This is a little sparse but the hour is late.

DROP TABLE IF EXISTS dispatch_log;
CREATE TABLE dispatch_log (
 dispatch_id SERIAL NOT NULL,  PRIMARY KEY(dispatch_id),
 time TIMESTAMP,
 description VARCHAR(255)
);

Credentials

To read dispatches I need access to email on a server so I need a place to keep those settings.

DROP TABLE IF EXISTS account;
CREATE TABLE account (
  user_id SERIAL NOT NULL,  PRIMARY KEY(user_id),
  login VARCHAR(40),
  password VARCHAR(40),
  server VARCHAR(40)
);

Everyone needs photo tables

I don't have the lo extension installed on Kilchis so I left this table out on that installation. Maybe not everyone needs photos.

Using lo (Large Object) extension to hold photo in database, I like to keep everything in one place so I don't lose them. (In the database instead of keeping them on the filesystem)

I could do photo/image processing in the database if I installed the PostPIC extension, see http://drotiro.github.com/postpic/ Possibly I could use it to generate the thumbnails?

DROP TABLE IF EXISTS photo;
CREATE TABLE photo (
 photo_id SERIAL NOT NULL,  PRIMARY KEY(photo_id),
 time TIMESTAMP,
 thumbnail BYTEA,
 image LO,
 lat NUMERIC(8,6), lon NUMERIC(9,6),
 title VARCHAR(80),
 description TEXT
);
CREATE TRIGGER t_image BEFORE UPDATE OR DELETE ON photo
   FOR EACH ROW EXECUTE PROCEDURE lo_manage(image);
-- Lat Lon are from iTouchMap.com
INSERT INTO photo (description) VALUES ('Davidson photo');
INSERT INTO photo (description) VALUES ('Fuji photo');
INSERT INTO photo (description,lat,lon) VALUES ('Bald Hill',44.56739,-123.332099);
INSERT INTO photo (description) VALUES ('New wheel photo');
INSERT INTO photo (description,lat,lon) VALUES ('Bellfountain Rd', 44.495692, -123.337787);
INSERT INTO photo (description,lat,lon) VALUES ('MG in Gold Beach',42.564287, -124.383210);
SELECT * FROM photo;

Photos are good for everything -- people, rides, vehicles, maintenance... so I need a junction table to accommodate this

DROP TABLE IF EXISTS j_photo;
CREATE TABLE j_photo (
 j_photo_id SERIAL NOT NULL, PRIMARY KEY(j_photo_id),
 photo_id INT NOT NULL, FOREIGN KEY (photo_id) REFERENCES photo(photo_id),
 trip_id INT, FOREIGN KEY (trip_id) REFERENCES trip(trip_id),
 rider_id INT, FOREIGN KEY (rider_id) REFERENCES rider(rider_id),
 vehicle_id INT, FOREIGN KEY(vehicle_id) REFERENCES vehicle(vehicle_id),
 maint_id INT, FOREIGN KEY (maint_id) REFERENCES maintenance(maint_id)
);
INSERT INTO j_photo (photo_id,vehicle_id) VALUES (1,1);
INSERT INTO j_photo (photo_id,vehicle_id) VALUES (2,2);
INSERT INTO j_photo (photo_id,trip_id) VALUES (3,3);
INSERT INTO j_photo (photo_id,maint_id) VALUES (4,2);
INSERT INTO j_photo (photo_id,trip_id) VALUES (5,3);
INSERT INTO j_photo (photo_id,vehicle_id) VALUES (6,6);
SELECT p.description,v.name
FROM j_photo AS j, photo AS p, vehicle AS v
WHERE ((j.photo_id=p.photo_id) AND (j.vehicle_id=v.vehicle_id));
SELECT p.description,m.notes
FROM j_photo AS j, photo AS p, maintenance AS m
WHERE ((j.photo_id=p.photo_id) AND (j.maint_id=m.maint_id));
SELECT p.description,t.notes
FROM j_photo AS j, photo AS p, trip AS t
WHERE ((j.photo_id=p.photo_id) AND (j.trip_id=t.trip_id));

Views

Views give me results that appear denormalized so that Wavemaker does not need to know about the joins. The problem is that you can't access tables for writing if they are in views. So these are read-only.

-- simplest case first
CREATE VIEW maintenance_view AS
SELECT date,name,maintenance.description FROM maintenance,vehicle WHERE maintenance.vehicle_id=vehicle.vehicle_id;
-- more complicated version
CREATE VIEW trip_view (date, mileage, notes, rider_name, vehicle_name) AS
SELECT t.date,t.mileage,t.notes,r.name,v.name
FROM trip AS t,rider AS r,vehicle AS v, j_trip AS j
WHERE (j.trip_id=t.trip_id) AND (j.rider_id=r.rider_id) AND (j.vehicle_id=v.vehicle_id);

Now I can use these tables in Wavemaker * read only *

Onward

That's enough to develop the sample app so go back to Wavemaker