The normal forms don't really have anything to do with many-to-many relationships. If you happen to lose some as a byproduct of the normalization process, that's fine, but you won't generally do so. If we consider that we have two tables: Salesman and Product which each have ID fields as their primary key and we have a third table called Specializes which shows which Salesmen specialize in selling which products. This Specializes table would represent the many-to-many relationship since each salesman can specialize in multiple products and each product can be specialized in by more than one salesmen. It would probably look something like this (excuse the awkward formatting, we can't do real tables on StackExchange):
| SalesmanID | ProductID |
|------------|-----------|
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 2 | 2 |
| 2 | 3 |
|------------|-----------|
Obviously, the lack of nulls and repeated rows means that this table is in 1NF. In this table, the only candidate key is {SalesmanID, ProductID} and as such, there are no non-prime attributes. It also contains no non-trivial functional dependencies. Thus, it is necessarily in 2NF, 3NF, and BCNF. I'm also going to assert without proof that it's in 4NF, 5NF, 6NF, and DKNF (to avoid having to explain all of the details thereof). So really, no normal form removes many-to-many relationships, nor are they meant to. The purpose of normal forms is not to remove many-to-many relationships (and I am not actually clear on why you would want to) but rather to remove potential insert anomalies, update anomalies, and deletion anomalies. The primary role of the normal forms is to ensure that each piece of information is represented in a database table precisely once. Having the same information embedded in multiple places leads to problems. But that has nothing to do with many-to-many relationships.
I think that you mean to be asking a slightly different question about something like situations where a many-to-many relationship is embedded in a table which also tries to contain other information, such as if the table above contained the product name in addition to the product number (where name is functionally determined by number). A table like that would either violate 2NF (if the name did not also functionally determine the number) or Boyce Codd Normal Form (if the name did functionally determine the number).
You could also perhaps be thinking of a different situation: when we have two unrelated 1:M relationships in the same table, such as if we were to add a third column to identify which language or languages each salesman speaks.
| SalesmanID | ProductID | Language |
|------------|-----------|----------|
| 1 | 1 | English |
| 1 | 2 | English |
| 2 | 1 | Spanish |
| 2 | 2 | Spanish |
| 2 | 3 | Spanish |
| 2 | 1 | French |
| 2 | 2 | French |
| 2 | 3 | French |
|------------|-----------|----------|
As you can see, that table is quite problematic, since we need 6 entries to express that Salesman 2 specializes in 3 products and speaks 2 languages. This is a fourth normal form violation.
Edit:
Upon clarification, it's clear that what he's asking about is a table like the Specializes table, but with extra information about the salesmen and the products, essentially, a table which contains two entity sets and their many-to-many relationship in a single table. So to answer that question directly, yes, you can have lousy tables like that which are in 3NF. The normal form which guarantees that that won't happen is Boyce-Codd Normal Form (BCNF). Here's an example of a lousy table like that which is vulnerable to all kinds of anomalies (insert, update, and delete), but is in 2NF and 3NF.
| SalesmanName | SalesmanID | ProductID | ProductName |
|--------------|------------|-----------|-------------|
| Alex | 1 | 1 | Thingy |
| Alex | 1 | 2 | Whatsit |
| Barb | 2 | 1 | Thingy |
| Barb | 2 | 2 | Whatsit |
| Barb | 2 | 3 | Whoosit |
|--------------|------------|-----------|-------------|
So, looking at this table, it's obviously in 1NF. Further, we can identify the non-trivial functional dependencies very straightforwardly. SalesmanName -> SalesmanID. SalesmanID -> SalesmanName. ProductID -> ProductName. ProductName -> ProductID. Next we need to identify the candidate keys. There are four: {SalesmanName,ProductID}, {SalesmanName,ProductName}, {SalesmanID, ProductID}, and {SalesmanID, ProductName}. As such, we have no non-prime attributes. Thus, we are necessarily in 2NF (no functional dependencies between non-prime attributes) and 3NF (no non-trivial functional dependencies where the left-hand-side is not a super key and the right hand side contains a non-prime attribute). However, we are not in BCNF because there do exist non-trivial functional dependencies whose left-hand-side is not a superkey.
Any similar situation will also always not be in Boyce-Codd Normal form because there will be some non-trivial functional dependency whose left-hand-side is not a superkey. Any table like this will essentially have two entity sets each of whom have some attributes. Basically, it will have a left entity set and a right entity set. The left entity set will have some attributes which uniquely identify each left entity and the right entity set will have some attributes which uniquely identify each right entity. Those will be involved in functional dependencies. However, they will each not be candidate keys because you'll have to combine them to get a candidate key for the whole table. As such, they won't be superkeys and there will be a Boyce-Codd Normal Form violation. So BCNF will stop it cold. Anything less than that will only catch some cases. Really, if you only remember one normal form, it should be BCNF.
Based on the details you've provided I'd say it sounds fine.
Things that may or may not be a problem based on further information.
(1) Even though you say there is no relationship between the two systems and no foreign key, if you were to switch third part systems, you would be left with a bunch of meaningless ids for books that were added from the previous 3rd part system. Is that okay? If not, you may need to add a lookup table of third party systems that can related to the IDs in the Book table so you can later tell which system they came from.
(2) If the only reason for the IDs from the third party system to be there is to check for their existence, maybe a simply IsFrom3rdParty or IsFreeForm boolean column would be sufficient. It would seem to meet all the requirements you lay out here and would be simpler than the ID to implement and would better convey the actual information you have (which is simply that it came from a 3rd party system. You can't guarantee that the ID will relate to anything especially if the backend system has changed)
Otherwise, yes it sounds good.
Best Answer
Your model completely ignores the fact that books come in multiple copies.
Each copy of a book can only be in one place at one time, but each place could have multiple copies of any given book.
Since each copy of a book will have exactly the same ISBN, the answer to your first question is: "No, ISBN is not a sufficient primary key for
Books
."What you need to account for is a
Title
entity. This is going to be a combination of what you're thinking about for yourBooks
entity. ATitle
is an abstract object. It will have a title, authors, publication date, and so forth. You might even want to consider making a distinction betweenTitle
andEdition
, since a book can be republished many times with variations each time.Whether or not you want to distinguish between editions of a title, you must at least distinguish between
Title
andBooks
. The answer to your second question is that each physical book will be in one place (either at aLibrary
or on loan to aMember
- or in transit between branches, or lost, etc. - depending on how sophisticated you want your model to be).On the other hand,
Title
s, (orEdition
s) will be many-to-many with locations.