Acces, multiple one to one connections question - ms-access

I have a problem with acces, im trying to make database of airport and cant realy make one to one - one to one - one to one connection beetwen ticket, passanger and luggage. The idea is that one passanger can have one ticket and one luggage, and when im doing it like it is on picture i cant acces luggage from ticket neither from passanger only from luggage itself.
My diagram

Mainly the diagram should be something like:
Simple Data and Keys:
Sample query(all tickets with relevant linked data):
SELECT Tickets.Ticket,
Tickets.Person,
Flights.Flight,
Luggages.Luggage
FROM Flights
INNER JOIN (
(Persons INNER JOIN Tickets ON Persons.ID = Tickets.Person)
LEFT JOIN Luggages ON Tickets.ID = Luggages.ID)
ON Flights.ID = Tickets.Flight;
Second view was the purpose, so it up to your side to do the adjustments.
Note:
Person 3 do not have luggage.
Person 1&2 use same flight.
MS Access was used, but design is not bound to a specific rdbms (only dialects adjustments for a particular implementation)
Also, there is an error on relation Persons-Tickets which should be 1-n.(similar Flight-Tickets).
Still additional constraints could be bound also.
Eg: a person can be just on one flight is a specific time.

Related

Db pattern for finding the owner of a record

I'm looking for a pattern for dealing with a situation where a record in a table may be related to 1 and only one of several other records and I need to know which. It's difficult to describe so I will use an example with an oauth client from a recent project.
A client has an id and secret and teams or users may own clients
clients
client_id|client_secret
user_clients
user_id|client_id
team_clients
team_id|client_id
The issue here is when someone attempts to use client credentials to get an access token I need to know if those credentials belong to a team or a user. I'm not really sure of the best way to deal with this, I control the database so changes can be made.
Some options I've considered:
Modify clients and remove user_clients and team clients
clients
client_id|client_secret|team_id(nullable)|user_id(nullable)
Create a client owners table and remove user_clients and team_clients
client_owners
team_id(nullable)|user_id(nullable)|client_id
Adding a type to the clients table and doing 2 queries or a conditional query
clients
client_id|client_secret|type(user or team)
Left joins and filtering/mapping in code.
select * from clients c left join user_clients u ... left join team_clients t ... where c.client_id = ?
None of these options feel great so I am wondering if there is a better pattern. This is a simplified example, sometimes these objects are much more complicated and have many more possible relationships so the queries can get pretty hairy and also difficult to manage when using an orm (though requiring raw sql for parts of the system is not an issue).
I'd love to hear how people are solving this problem.
Thanks in advance.
Design
What you describe are 1:n relations:
One user can own multiple clients
One team can own multiple clients
So, the first approach seams appropriate: The client table has a user column and a client column.
Now you say a client can only be owned by either a user or a client. You would have a check contraint on the client table for this to ensure that only one of the IDs is set. (And if every client must have an owner, this constraint would also care about this.)
Some example queries
If you want to get all clients owned by users:
select * from clients where user_id is not null;
If you want to know whether a client is owned by a user or a team:
select
c.*,
case when user_id is not null then 'user'
when team_id is not null then 'team'
else 'none'
end as owner
from clients c;
If you want user or team information:
select c.*, coalesce(u.name, t.name) as owner_name
from clients c
left join users u on u.user_id = c.user_id
left join teams t on t.team_id = c.team_id;
The idea with the left joins is something you can go with. Leave your clients table with just clientID and left join it on user_clients and team_clients.
You could also combine that with your first option and add a column for user_clientsID and team_clientsID and at adding to the left join clients.user_clientsID <> 0 which is going to help you with the.
The 2nd and 3rd option is something I have seen used as well. With the second option perhaps being the one that can sometimes create the most headaches.
Also an option you can consider is creating a view table with all the information you might need

Access Rental Database: Preventig an equipment to be used in two different projects

I'm looking for a way to make a database for equipment managment but I don't know how to go forward from my point.
I have now 3 core tables to do this part, the EQUIPMENT table, where I have a list of all the equipment I have (with the different units on record and everything),
besides this one I have the PROJECT table, where I have all the information of the rental service and I also have a PROJECT_DETAILS where I place the equipment for the given project
Examples:
EQUIPMENT TABLE: Brand,Model,Internal Number:
[Ford;Transit; 1][Ford;Transit;2][Ford;Transit;3][Mercedes;Sprinter;1][Mercedes;Sprinter;2] Etc...
PROJECT TABLE: Project code, Start, End, Client Name:
[XX001;2016/08/05;2016/08/10;Steve][XX002;2016/08/06;2016/08/8;Bill] etc...
PROJECT DETAILS: Project Code, Equipment, Internal Number:
[XX001;Transit;1][XX001;Transit;2][XX002;Transit;3][XX002;Sprinter;1]
So what I want to do is when trying to make a new project, I want the equipment to dissapear from its combo box if the equipment is in use in another project
I would continue to flesh out the database schema with the following additional tables:
RENTAL: This represents "the rental contract itself." The rental might be active, or it might be being contemplated. Perhaps, all RENTALs belong to (one) PROJECT ...
RENTAL-EQUIPMENT: This one-to-many table lists the items that are to be rented when this rental contract goes into effect.
RENTAL-EQUIPMENT-RESERVED-NOW: This is “where the rubber hits the road.” This table contains an entry for every piece of EQUIPMENT that is "right now, irrevocably, 'off the lot.'" It is related both to RENTAL-EQUIPMENT (to justify the presence of the record), and directly to EQUIPMENT ("where's that dump truck and why is it not here on the lot? Oh. We rented it. I see..."). I'd probably insert a record into the table when the equipment went out the door, and remove the record when the equipment was returned. The presence of a row in this table ... only one row per equipment_id is allowed ... is sufficient to indicate that a piece of equipment is reserved or off-the-lot, and why.
In this view of things, PROJECTs, from time to time, "rent things," or "plan to rent things in the future." (Nobody rents anything unless it is associated with a project, say...) Each RENTAL consists of a list of equipment to be rented. Then, when stuff goes off-the-lot and we need to be able to quickly(!) account for it (without poring through a bunch of RENTAL-EQUIPMENT and RENTAL records in a very-laborious query ...), the RESERVED-NOW table gives us an immediate answer.
You should also familiarize yourself with the concept of TRANSACTIONs, which Access fully supports. A "transaction" is an atomic group of SQL statements that will be "all or nothing." For instance, when you start to process the departure of a piece of equipment from the lot, you "start a transaction." Then, you perform the SQL statements needed to insert into RENTAL-EQUIPMENT-RESERVED-NOW and to update RENTAL-EQUIPMENT records and so-on ... then, you "COMMIT the transaction." All of the changes that you made, all at once, then "become permanent."
What? "Oopsie! Something went wrong!!" No problem: just ROLLBACK the transaction instead, and you're right back where you started. Nothing that you did during the transaction 'actually happened.' (Rollbacks often appear in on error goto... blocks.)
Finally, also look at things like "foreign keys" and "referential integrity."
I think something like this would work. Basically depending on on how your project is set up, you would want to look at anything where the end date is past your current client trying to schedule "schedule_date" let's say and before or equal to the schedule_date. This way if they select a date range, anything that is between those dates wouldn't show up.
SELECT * FROM equipment WHERE internal_number NOT IN (SELECT internal_number FROM project INNER JOIN project_details ON product_details.project_code = project.project_code WHERE end_date >= schedule_date and begin_date <= schedule_date)
From the way I read your question, it sounds like ProjectDetails is recording the combinations of the project and the equipment. It also sounds like you aren't interested in keeping a historical of those assignments, and are therefore removing them from projectdetails when they are no longer assigned.
So (again, if I understand correctly), what you want to do is to show all of the records in the equipment table that does not exist in the projectdetails table - correct?
SELECT * FROM equipment INNER JOIN projectdetails ON equipment.equipid = projectdetails.equipid
I broadly concur with DHW and Mike Robinson - From my reading of your structure you are using the project details table as a junction table to relate the equipment and the projects. Comparison of this table to the equipment should give a list of all unused equipment.
I had a go on an access database at my end and I joined the Equipment Table to the Project Details Table and did a left join so that ALL equipment was shown. I then added the Equipment field of the Project Details table. In order for this to work you need a relationship between the Project Details Table and the Equipment table and you must ensure the Project Details Equipment Field and the Equipment Table Internal Number are same data type ie Long Integer. I then ensured then put a filter on the Project Details.Equipment field criteria set to Null. The SQL I used for this was
SELECT EquipmentTable.InternalNumber, EquipmentTable.Brand,EquipmentTable.Model, ProjectDetails.Equipment FROM EquipmentTable LEFT JOIN ProjectDetails ON EquipmentTable.InternalNumber = ProjectDetails.Equipment WHERE (((ProjectDetails.Equipment) Is Null));

SQL in PHPMYADMIN

I help with an SQL (using phpmyadmin) to join these tables and create a CLUB MEMBERSHIP list for a particular club, however I need to indicate whether the member is a club president, vice president,etc or just an ordinary member:
CLUBS: CLUBID,PRESIDENTID(memberID),VICEPRESIDENTID(memberID),TREASURER(memberID),
SECRETARY(MemberID)
MEMBERS_CLUB:
MEMBERID,CLUBID
MEMBERS:
MEMBERID, NAME,ADDRESS
There are probably half a dozen ways to solve this, and you certainly could come up with a way to make this table structure work for you, but it's probably not going to be pretty. Part of making this work well is determining what information you need to get out as well as store in the database. In this structure, it's very hard to get the member's officer status from their name, so we can improve that by changing your structure. On the other hand, if all you ever needed was a list of officers for each club, your current structure would be okay.
You could add a "member status" field to MEMBERS_CLUB (and remove the four corresponding columns from CLUBS). Each member gets a row for each club or position they hold.
SELECT `MEMBERS`.`NAME`, `MEMBERS_CLUB`.`STATUS`, `CLUBS`.`CLUBID`
FROM `MEMBERS`, `MEMBERS_CLUB`, `CLUBS`
WHERE `MEMBERS`.`MEMBERID` = `MEMBERS_CLUB`.`MEMBERID`
which is close but gives us duplicates if there are duplicates in the table, for instance if you have two entries for Bob, one listing him as president and one listing him as secretary. By using GROUP_CONCAT() we can accomplish exactly what you are looking for while dealing properly with duplicated names:
SELECT `MEMBERS`.`NAME`, GROUP_CONCAT(`MEMBERS_CLUB`.`STATUS`), `CLUBS`.`CLUBID`
FROM `MEMBERS`, `MEMBERS_CLUB`, `CLUBS`
WHERE `MEMBERS`.`MEMBERID` = `MEMBERS_CLUB`.`MEMBERID`
GROUP BY `NAME`

best practice database design for tracking progress through related tables (multiple left joins)

I have a django database application, which is constantly evolving.
We want to track the progress of samples as they progress from
sample -> library -> machine -> statistics, etc.
Generally it is a one to many relationship from each stage left to right.
Here is a simplified version of my database schema
table sample
id
name
table library
id
name
sample_id (foreign key to sample table)
table machine
id
name
status
library_id (foreign key to library table)
table sample_to_projects
sample_id
project_id
table library_to_subprojects
library_id
subproject_id
So far it has been going ok, except now, everything needs to be viewed by projects. Each of the stages can belong to one or more projects. I have added a many_to_many relation between project and the existing tables.
I am trying to create some views that do the multiple left joins and show the progress of samples for a project.
sample A
sample B library_1 machine_1
sample B library_2 machine_2
sample C library_3
first try at the query was like this:
SELECT fields FROM
sample_to_projects ,
sample
LEFT JOIN library ON sample.id = library.sample_id ,
library_to_project
LEFT JOIN machine ON machine.library_id = library.id
WHERE
sample_to_project.project_id = 30
AND sample_to_project.sample_id = sample.id
AND library_to_project.project_id = 30
AND library_to_project.library_id = library_id
The problem here is that the LEFT JOIN is done before the WHERE clause.
So if we have a sample that belongs to project_A and project_B.
If the sample has a library for project_B, but we want to filter on project_A, the LEFT JOIN does not add a row with NULLs for library columns (as there are libraries). However these rows get filtered back out by the WHERE clause, and the sample does not show up.
reults filtering on project_A
sample_1(project_A, project_B) library_A (project_A)
sample_1(project_A, project_B) library_B (project_A, project_B)
sample_2(project_A, project_B) library_C (project_B) *this row gets filtered out, it should show only the sample details*
So my solution is to create a subquery to join the other (right hand side) tables before the LEFT JOIN is done.
SELECT fields FROM
sample_to_projects ,
sample
LEFT JOIN (
SELECT library.id as lib_id , library.sample_id as smaple_id , library.name as lib_name , machine_name
FROM library ,
lib_to_projects ,
machine
)
AS join_table ON sample.id = join_table.sample_id
WHERE
sample_to_project.project_id = 30
AND sample_to_project.sample_id = sample.id
The problem is that there are a few more stages in the real version of my database, so I will need to do a nested subquery for each LEFT JOIN. The SQL will be getting pretty large ad difficult to read, and I wondered if there is a better solution at the design level? Also it won't play nicely with Django models (though if I can get the SQL working I will be happy enough).
Or can anyone suggest some sort of best practices for this type of problem? I am sure it must be relatively common with showing users in groups or something similar. If anyone knows a way that would fit well with django models that would be even better.
What about creating sepatate views for each Project_Id?
If you leave the database structure as is and add to it as the application progresses. You can create a separate view for each stage or Project_Id. If there are 30 stages (Project_Id 1..30) then create 30 separate views.
When you add a new stage... create a new view.
I'm not precisely clear on what you're using this for, but it looks like your use-case could benefit from Pivot Tables. Microsoft Excel and Microsoft Access have these, probably the easiest to set up as well.
Basically, you set up a query that joins all your related data together, possibly with some parameters a user would fill in (would make things faster if you have large amounts of data), then feed the result to the Pivot Table, and then you can group things any way you want. You could, on the fly, see subprojects by library, samples by machine, libraries by samples, and filter on any of those fields as well. So you could quickly make a report of Samples by Machine, and filter it so only samples for machine 1 show up.
The benefit is that you make one query that includes all the data you might want, and then you can focus on just arranging the groups and filtering. There are more heavy-duty systems for this sort of stuff (OLAP servers), but you may not need that if you don't have huge amounts of data.

SQL Multiple Inner Joins on the same field

I am currently working as a programmer in a small startup aiming on providing pay-per-view content online and I have been assigned to develop the metadata database for the movie catalogue
I have two main tables, movie and people, where *movie_ID* and *people_ID* are the primary keys respectively for each table. Both tables have a many-to-many relationship.
To represent different relations I am currently using link tables, for example, actor_movie would store the *movie_ID* and corresponding *people_ID* for each of the actors in the movie, while the director_movie table would store the *movie_ID* and the director(s) *people_ID*. Same goes for writer, composers and producers.
Now, my problem is that I need to craft out a query that returns all the actors, directors, producers, writers, composers, etc. etc. in one single table to be passed on the frontend Web UI as a list of all the persons involved in the movie.
I'm currently stumped as to how to create a multiple SELECT query that would JOIN all the link tables together based on the *movie_ID* and *people_ID* and then return the details of each of the person in the people table as well.
And example of what I have written so far is:
SELECT
movie.titleMovie,
people.namePeople,
FROM
movie movie
INNER JOIN actorlinkmovie acm ON acm.idMovie = movie.idMovie
INNER JOIN people people ON people.idPeople = acm.idPeople
What I would like to have happen is:
SELECT
movie.idMovie,
movie.titleMovie,
movie.descMovie,
movie.dateMovie,
movie.runtimeMovie,
movie.langMovie,
movie.ratingMovie,
people.namePeople
FROM
htv_movie movie
INNER JOIN htv_actorlinkmovie acm ON acm.idMovie = movie.idMovie
INNER JOIN htv_directorlinkmovie dcm ON dcm.idMovie = movie.idMovie
INNER JOIN htv_producerlinkmovie pcm ON pcm.idMovie = movie.idMovie
INNER JOIN htv_people people WHERE people.idPeople = dcm.idPeople AND people.idPeople = acm.idPeople AND people.idPeople = pcm.idPeople
And it should return the all the related people from a single movie.
Would like to get some input about the whole design since I'm a pretty new at designing a whole database (first time actually) and whether would this design be suitable if I need to scale up to about 5000 movies (the current company aim). This database will pretty much serve as the website's backend as well.
Thanks.
UPDATE: Temporarily worked out a dirty solution using PHP variables and a template SQL query. Looks like doing multiple inner joins wasn't that required after all. Thanks for the suggestions though.
You can achieve your goal like this:
SELECT MovieName,
dbo.GetDirector(MovieID),
dbo.GetActors(MovieID),
dbo.GetWriter(MovieID) FROM Movie
where
dbo.GetDirector(MovieID) is a
function that will return directors
in the movie.
dbo.GetActors(MovieID) is a function
that will return actors in the movie.
dbo.GetWriter(MovieID) is a function
that will return writers in the
movie.
If there are some other tables then you can make functions for those tables as well.
Hope this helps.