I have a table for person and a table for language. Each person can speak up to 4 languages. My client wants to search for people that can speak, for instance Spanish.
My problem is that the results table currently won't have a column called Language because they will speak more than one. I could display just the first one, but it will be misleading to hide the other languages that they speak.
The table could have a column for each language, and fill in NULL if they don't have all 4 languages, i.e.:
Language 1
Language 2
Language 3
Language 4
But this seems very sloppy.
I have considered listing all of the languages in a single column, using a comma separated list, but this is know good for sorting the column alphabetically.
Currently, I am having to tell my client that the results table can only show columns where the person has one of them (1 to 1), i.e. name, location, native language etc. Only when the client clicks on that person, can it reveal all of their languages.
Does anyone know if there is a common way to solve this? Hope this makes sense
I do have an association table. The problem is that my search will return
joe bloggs, gotham city, spanish
then
joe bloggs, gotham city, french
on the next row - but then the same person is listed twice in the table. When I restrict it to one entry per name, I just get "joe bloggs, gotham city, spanish". Now I don't know that he also speaks french. Is this clearer?
You should have a join table which contains two fields: person and language. There should be one row per person per language, so if one person speaks four languages, there would be four rows for this user.
The primary key for this table would comprise both fields.
Then to get a list of which people speak Spanish, you would need a query like
select people.name
from people inner join p2l
on people.id = p2l.person
inner join languages
on p2l.language = languages.id
where languages.name = 'Spanish'
And a list of all people who speak a language
select people.name, languages.name
from people inner join p2l
on people.id = p2l.person
inner join languages
on p2l.language = languages.id
And now a list of all people, whether they speak a language or not
select people.name, languages.name
from people left join p2l
on people.id = p2l.person
inner join languages
on p2l.language = languages.id
Having thought about this some more, it seems that you have the following options
Use the simple join/link/association table that both Christophe and I suggested, then massage the data in the program which calls the SQL. This is the simplest route to take.
Maintain a comma delimited list of languages along with the join table. The join table will allow you to answer queries such as 'who speaks Spanish', whereas the list will enable you to print out a list of languages per person. Maintaining this list will be a problem.
Use the 'dedicated field per language' approach of Ravindra; every time you need a new language, you will have to change the field structure, thus this approach is very much not recommended.
Use a cross tab query; this is quite hard to do and depends on which flavour of SQL you are using. Look at this article creating-cross-tab-queries-and-pivot-tables-in-sql.
In my option, option 1 is the best and easiest. SQL is great at what it does and terrible at what it doesn't do, so it's best to take the best parts of SQL and surround them with the best parts of a declarative language.
So the traditional way to solve this is to create something called an association table, which has foreign keys to both the person and language tables. This lets you add an arbitrary number of languages (including zero). Then you can join accross these tables to find all users speaking a specific language.
This may help with how to structure databases: http://en.wikipedia.org/wiki/First_normal_form
There's higher normal forms, but this will help you solve your current problem.
create two table
person having cloumns- person_id,person_name & more if u want.
create another table -Language having columns-person_id,lang1,lang2,lang3,lang4
make person_id as foreign key
now when u want to access languages, just fetch them by compairing person_id
SELECT p.person_id
FROM person p, language l
WHERE p.person_id = l.person_id;
Related
First time poster and enthusiastic Access newbie.
I've got a search screen based on Allen Browne's wonderful search in vba (http://allenbrowne.com/ser-62.html). This has worked great for most of my purposes, but now a child table is duplicating records.
Our clients(providers), can be enrolled in multiple programs. we've got four. I want a search that let's me filter by provider type, but not create duplicate records when a provider is enrolled in more than one provider type. In the example image, carmen titus is in the LEHRC and fccn programs, and therefore shows up twice. Tried to post pic but no dice.
Please help! I searched diligently and could not find a solution. I'd appreciate the support or to be pointed to a related post. I hope this makes sense. I think half my battle as a self-trained newbie is not knowing the terminology.
We'll need more info!
It sounds like the query you are basing the search on contains columns from two tables with a one to many relationship ie clients and "Client programs", such that a single client has zero to 4 programs.
It sounds like you only want to return a list of providers (ie rows on the one side), but your SQL is returning data from both tables.
Here's what you SQL might need to look like to do what you need:
SELECT *
FROM clients AS mainClient
WHERE
EXISTS
(SELECT 1
FROM clients AS C
LEFT JOIN ClientPrograms AS CP
ON C.ID = CP.ClientID
WHERE mainClient.ID = C.ID
' the above line links the EXISTS "Sub query" to the main query
AND client name like "*j*" ... etc...
... ie lots of criteria generated by you popup search criteria dialogue)
)
By adding the EXISTS statement the main query will be editable.
If you had used SQL like the following you would not be able to edit it
SELECT c.name, c.dob, etc.. ie all the field you want on the form whichwill all be from the client table
FROM clients AS C
LEFT JOIN ClientPrograms AS CP
ON C.ID = CP.ClientID
WHERE mainClient.ID = C.ID
' the above line links the EXISTS "Sub query" to the main query
AND client name like "*j*" ... etc...
... ie lots of criteria generated by you popup search criteria dialogue)
GROUP BY all the field in the select statement
I hope this gives you some inspiration
I have a table Things and I want to add ownership relations to a table Users. I need to be able to quickly query the owners of a thing and the things a user owns. If I know that there will be at most 50 owners, and the pdf for the number of owners will probably look like this, should I rather
add 50 columns to the Things table, like CoOwner1Id, CoOwner2Id, …, CoOwner50Id, or
should I model this with a Ownerships table which has UserId and ThingId columns, or
would it better to create a table for each thing, for example Thing8321Owners with a row for each owner, or
perhaps a combination of these?
The second choice is the correct one; you should create an intermediate table between the table Things and the table Owners (that contains the details of each owner).
This table should have the thing_id and the owner_id as the primary key.
So finally, you well have 3 tables:
Things (the things details and data)
Owner (the owners details and data)
Ownerships (the assignment of each thing_id to an owner_id)
Because in a relational DB you should not have any redundant data.
You should definitely go with option 2 because what you are trying to model is a many to many relationship. (Many owners can relate to a thing. Many things can relate to an owner.) This is commonly accomplished using what I call a bridging table. (Which exactly what option 2 is.) It is a standard technique in a normalized database.
The other two options are going to give you nightmares trying to query or maintain.
With option 1 you'll need to join the User table to the Thing table on 50 columns to get all of your results. And what happens when you have a really popular thing that 51 people want to own?
Option 3 is even worse. The only way to easily query the data is to use dynamic sql or write a new query each time because you don't know which Thing*Owners table to join on until you know the ID value of the thing you're looking for. Or you're going to need to join the User table to every single Thing*Owners table. Adding a new thing means creating a whole new table. But at least a thing doesn't have a limit on the number of owners it could possibly have.
Now isn't this:
SELECT Users.Name, Things.Name
FROM Users
INNER JOIN Ownership ON Users.UserId=Ownership.UserId
INNER JOIN Things ON Things.ThingId=Ownership.ThingId
much easier than any of those other scenarios?
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`
In an RPG game a character can choose from a list of skills, which in turn are stored in a unique skill list for that character.
The problem being that there is still a many to many relationship between skills and skill list that I would like to resolve.
I've read through the other articles and I am still none the wiser, can anyone shed some light on this problem.
Thanks in advance.
I don't understand why there would be a many to many relationship between skills and skill list. That sounds like a many to one relationship. But if you really mean you are trying to link the characters to the skills then:
You will need a third table that links the skills table to the characters table, something like the following:
Table: characterskills
characterid
skillsid
Then using SQL you can retrieve a master list of all characters and all of their skills:
SELECT c.charname, s.skillname FROM
characters AS c
INNER JOIN characterskills AS cs ON cs.characterid = c.id
INNER JOIN skills AS s ON cs.skillsid = s.id
Here is the SQL Fiddle demonstrating the above.
I have a MYSQL database containing the names of a large collection of people. Each person in the database could could have one or all of the following name types: first, last, middle, maiden or nick. I want to provide a way for people to search this database to see if a person exists in the database.
Are there any off the shelf products that would be suited to searching a database of peoples names?
With a bit of ingenuity, MySQL will do just what you need... The following gives a few ideas how this could be accomplished.
Your table: (I call it tblPersons)
PersonID (primary key of sorts)
First
Last
Middle
Maiden
Nick
Other columns for extra info (address, whatever...)
By keeping the table as-is, and building an index on each of the name-related columns, the following query provides an inefficient but plausible way of finding all persons whose name matches somehow a particular name. (Jack in the example)
SELECT * from tblPersons
WHERE First = 'Jack' OR Last = 'Jack' OR Middle = 'Jack'
OR Maiden = 'Jack' OR Nick = 'Jack'
Note that the application is not bound to only searching for one name value to be sought in all the various name types. The User can also input a specific set of criteria for example to search for the First Name 'John' and Last Name 'Lennon' and the Profession 'Artist' (if such info is stored in the db) etc.
Also, note that even with this single table approach, one of the features of your application could be to let the user tell the search logic whether this is a "given" name (like Paul, Samantha or Fatima) or a "surname" (like Black, McQueen or Dupont). The main purpose of this is that there are names that can be either (for example Lewis or Hillary), and by being, optionally, a bit more specific in their query, the end users can get SQL to automatically weed-out many irrelevant records. We'll get back to this kind of feature, in the context of alternative, more efficient database layout.
Introducing a "Names" table.
Instead (or in addition...) of storing the various names in the tblPersons table, we can introduce an extra table. and relate it to tblPersons.
tblNames
PersonID (used to relate with tblPersons)
NameType (single letter code, say F, L, M, U, N for First, Last...)
Name
We'd then have ONE record in tblPersons for each individual, but as many records in tblNames as they have names (but when they don't have a particular name, few people for example have a Nickname, there is no need for a corresponding record in tblNames).
Then the query would become
SELECT [DISTINCT] * from tblPersons P
JOIN tblNames N ON N.PersonID = P.PersonID
WHERE N.Name = 'Jack'
Such a layout/structure would be more efficient. Furthermore this query would lend itself to offer the "given" vs. "surname" capability easily, just by adding to the WHERE clause
AND N.NameType IN ('F', 'M', 'N') -- for the "given" names
(or)
AND N.NameType IN ('L', 'U', 'N') -- for the "surname" types. Note that
-- we put Nick name in there, but could just as eaily remove it.
Another interest of this approach is that it would allow storing other kinds of names in there, for example the SOUNDEX form of every name could be added, under their own NameType(s), allowing to easily find names even if the spelling is approximate.
Finaly another improvement could be to introduce a separate lookup table containing the most common abbreviations of given names (Pete for Peter, Jack for John, Bill for William etc), and to use this for search purposes (The name columns used for providing the display values would remain as provided in the source data, but the extra lookup/normalization at the level of the search would increase recall).
You shouldn't need to buy a product to search a database, databases are built to handle queries.
Have you tried running your own queries on it? For example: (I'm imagining what the schema looks like)
SELECT * FROM names WHERE first_name='Matt' AND last_name='Way';
If you've tried running some queries, what problems did you encounter that makes you want to try a different solution?
What does the schema look like?
How many rows are there?
Have you tried indexing the data in any way?
Please provide some more information to help answer your question.