I have a database with two tables: Users and Categories.
Users has these fields:
UserId unique identifier
UserName nvarchar
CategoryId int
Categories has these fields:
CategoryId int
CategoryName nvarchar
At the moment, every user is in one category. I want to change this so that each user can be in any number of categories. What is the best way to do this?
My site does a lot of really expensive searches, so the solution needs to be as efficient as possible. I don’t really want to put the list of categories each user has in a third table, as this means that when I pull back a search, each user will be represented in several rows at once (at least, this is what would happen if I implemented a search with my current, fairly crude, understanding of sql.)
EDIT:
If setting up a many-many relationship, is it possible to return only one row for each user?
For instance:
DECLARE @SearchUserID nvarchar(200) = 1;
SELECT *
FROM Users JOIN Categories JOIN CategoriesPerUser
WHERE UserId = @SearchUserID
This would return one row for each category the user belonged to. It is possible to have it only return one row?
At the moment you have a one-to-many relationship, that is to say category can be assocaited with many users, but a user can only be assocaited with one category.
You need to change this to a many-to-many relationship so that each user can be assocaited with many categories and each category can be assocaited with many users.
This is achieves by adding a table which links a userid and a category id (and removing categoryid from the user table)
As for your last paragraph, this is the most efficient way of modelling your requirement. You should make a combination of UserId/CategoryId the PrimaryKey in this table to stop a user being associated with the same category twice. This stops the problem of a user returned twice for a particular category.
The SQL to find, for example, all users associated with a category would be
Edit after comments: If you have a query that finds a number of users, and you want a distinct list of categories associated with those users this could be done like