I have implemented search for my customers master successfully, and it searches the entire customer master.
I have agents logged in who are doing the searching. Customer accounts are associated with agents. I need to restrict the search to customers associated to the agent (who is logged in).
How do I do this?
You will need to scope your data and your sql statements to the current user.
For instance, let's say you have a table sales and a table users. Functionally, each sale belongs to a user. As such, the sales table should have a foreign key on it such as user_id that identifies, for each sale row, the row in the users table to which that sale belongs.
Then, when you search through sales, you should always add "where user_id = ?" as the first filter of your sql statement, before the other dynamic filters, replacing ? with the id of the current logged in user.
In this manner, all the filter criteria when searching the sales table will first be scoped to the current logged in user. If the filter criteria would otherwise pick up someone else's sales rows, it will no longer do that due to the user_id filter.
If you have sales that pertain to all agents in addition to those that are agent-specific, they would presumably have some marker, either an agent_id of 0 or perhaps NULL, or some other field that identifies them as searchable by all. This can easily be worked into that first WHERE fragment in the SQL statement with appropriate parentheses to keep it together:
WHERE (agent_id = ? or agent_id IS NULL) AND other dynamic filter etc
WHERE (agent_id = ? or agent_id = 0) AND other dynamic filter etc
WHERE (agent_id = ? or all_agents_flag = 1) AND other dynamic filter etc
Seems like you need to LEFT JOIN. Why don't you LEFT JOIN the tables that are in question. For ex: orders, sales_agents, customers...
Might just work.
Related
So I have two different tables, a users table and an articles table. The idea is to allow a user to rate an article, but only allow them to rate it once (possible change their existing rating too but I can come to that conclusion later).
As of now I just have the update value working to allow them to rate the article, but of course a user can rate an article as many times as they want.
To give you an idea of how I have everything working, when a user logins in, a session is created with their user information. So when they go to rate an article, I have the ability to check the user, I just don't know how to stop them from rating if they have already rated a specific article.
The user table consists of among other things their username and their unique ID
and the article table consists among other things the article contents, the article unique ID, and the articles rating.
I had some really sloppy ideas like when the user rates an article their ID gets stored into the articles row in some kind of "users who have rated" column, and then I can do a for loop or something to siphon out all the user IDs and then check if their ID exists in that articles entry but then each article would have a row with possibly hundreds or thousands of userIDs on it and there seems like there would be a more elegant way.
Any help or direction is appreciated :)
Create a UserRatings table which has foreign keys to the users table and the articles table, and stores a row linking the user to the article, and the rating they gave it and when it occurred.
Then if a user tried to rate it again you just check this table for the user ID/article ID combination before allowing it.
And then if you wanted got can do things like show the user a list of articles they have previously rated, etc
In an application I've been building, I have a users table. The users represent a firm's staff. I also implemented a role/permission system. Permissions are assigned to roles (staff, manager, director, etc.), and roles are assigned to users. Permissions prohibit the use of certain actions in the app.
Now, I'm introducing another user type: customer (will also be able to log into the app). The customer fields are different from the user fields, so I can't store the customer information in users table (and create a role for customers).
(Normally, just creating a customer role for the customers and store the custumers in the users table would be fine, but since the fields are different, I don't think that's an option.)
First, I thought about creating a seperate table for the customers, but I'm not sure if that's okay, because when someone tries to log into the app, I have to check two tables (users and customers) for the log-in credentials. What if I introduce a third user type? Check three tables? That doesn't seem practical/efficient.
So I thought about seperating the log-in credentials from users, and ended up with three tables:
users will hold log-in credentials
staff will hold staff meta/profile information
customers will hold customer information (same as staff)
This way, I can introduce many different types of users. And if I know what I'm looking for, I can get the record. For example, say I want to get/query a staff, I can just do:
SELECT * FROM staff
JOIN users USING (user_id);
The problem is how do I query users when I don't know what I'm looking for? I mean, the logged user can be a staff, customer, etc. I need to do something like this:
SELECT * FROM users
JOIN [specific_table_name] USING (user_id);
How do I know which type of user just logged in? I could store the user type (the target table name?) in users, but will it help in a (single) query? I mean, find the user in users (using credentials), and then join the user information from another table (staff, customers, etc.)?
Currently, I'm thinking about doing two queries. First is to get the user (credential) record, and the second is to get user (say, profile) information (using a field type from user record).
Of course I'll be doing this in PHP. For example (not real code):
$email = "someone#example.com";
$user = get_user($email); // SELECT * FROM users WHERE email = "someone#example.com"
switch ($user["type"]) {
case "staff":
$user = get_staff($email); // SELECT * FROM staff JOIN users USING (user_id) WHERE email = "someone#example.com"
break;
case "customer":
$user = get_customer($email);
break;
// ...
}
// how it's done doesn't really matter. the thing is "type" needs to be checked to get the corresponding user info
Is this best way to handle this? Is there a way to make the queries in SQL (without resorting to PHP)? Like JOIN after WHERE? Or make two queries in one (save the first query result, and use a column value from the first result as a table name in the second query)?
Mentioned tables:
I'm still researching, and I found out that what I'm doing with the tables is called (?) "Class Table Inheritance". It seems clever for non-login related entities (when going from child to parent; e.g. staff -> user), but in reverse (parent to child, e.g. user -> staff|customer|etc.), it seems problematic. Since I figure these things as I go, I'm stuck at the moment.
One solution that just (while typing) occured to me is to use different log-in forms/pages specific to user types. The form/page could let me know the user type beforehand, but I rather not use this method. So, single log-in form for all users.
I'm calling users as the base/parent table, and the stuff, customers, etc. as the child tables, because first insert happens at users, and child tables use user_id from users.
You could create a union and use an alias in the query to define different fields mapping for the same name, if there is no field in one table you just cast the alias for an empty field:
SELECT (staff.name) as name FROM users
left JOIN staff USING (user_id)
UNION
SELECT (customers.first_name) as name FROM users
left JOIN customers USING (user_id);
If the userId is a PK/FK it will be only returned by one table.
I would set all users login info and email to the parent table (customers and staff) and two tables with foreign id key for other data, with users.type as you suggested. It could be done with one query, too and Switch condition is not needed:
SELECT users.email,users.type,staff.field2,customers.field3 from users
LEFT JOIN staff ON(users.type='staff' and users.id=staff.uid)
LEFT JOIN customers ON(users.type='customers' AND users.id=customers.uid);
I have to develop a shopping site where I need to maintain data like "Add to Cart" and "Previous Orders" for a single user, for N number of users in a database. E.g. if there is a user named "Mark" and I need to store his 5 items previously added to cart and 4 items as previous order and there are say 100 users like him whose data I need to store, How should I solve this problem? I am using PHP and MySQL.
Each user is assigned a unique ID (you can exploit MySQL's AUTO_INCREMENT for this purpose when creating the table of users.
Then, for items the users select, you create another table including the User_ID (from the previous table), the Item_ID (from a similar table for items), the status (that would indicate the status of the item for the specific user) and an optional field that would contain the order number when the user places the order (for one or more items).
In summary, and since you are actually asking for help in designing your database, I would suggest you sit with a pencil and a piece of paper and make lists of informational elements that you need, marking the one-to-one relation between them (when applicable). This will (approximately) suggest what needs to be arrange in a record of a table (e.g. all the stable details of a user would normally go together into a single table).
I am building a web application that has users and orders. I have a question about how to handle the relationship between the two.
An order belongs to a user. But here's the twist, a user can optionally choose to outsource an order to another user.
When an order is outsourced, the original user still remains the owner and only he can modify certain things like price, quantity etc on the order.
The user the order is outsourced to can view some of the order information and can update specific properties on the order like marking as fulfilled.
An outsourced order should show up on both users "orders index".
All the users are "equal" meaning on certain orders a user might be the owner and on others he might be fulfilling the order. A user can also fulfill his own orders.
It doesn't seem like a true many to many relationship as one of the users doesn't really own the order, he just has limited access to it.
What would be the simplest way to handle this order/users relationships? I would like to avoid using a complete permission system, is there a way to simply handle this with an "outsourced" table? How about having a user_id and outsourced_to field on the order table?
Thanks for your input!
If it's of any help, the application uses Laravel.
It seems like your Orders table has two separate relationships with the Users table.
Orders have an owns/owned-by relationship to Users.
Users(1) -- owns -- (*)Orders
One User can own many Orders. One Order is owned by only one User
Then there is a completely separate outsourced-to relationship between Orders and Users.
Orders(*) -- outsourced-to -- (1)Users
(Here I assume that an Order can only be outsourced to one other User. A User may have many Orders outsourced to them.)
The best way to represent this is to have the Orders table have a 'owner' foreign key column into the Users table and another 'outsourced_to' foreign key column also to the Users table.
What columns of Orders the outsourced user can edit will be controlled by the code and not by the dB.
A separate outsourced table will be needed only if Orders can be outsourced to multiple Users at the same time.
How about having a user_id and outsourced_to field on the order table?
Sounds good.
Also, think about a kind of de-normalization, like moving fields, which editable by "outsorced-to" user to separate table.
I already have a simple registration system in place using php and mysql. It operates well enough. However, when people visit my site and register, I would like for them to register as part of a particular group. So, I was thinking that registration would happen like this:
Visitor lands on index.php, clicks on "Group Registration" link.
Visitor supplies group name and group password. [A new table is created for that group where all user data will be stored for that particular group]
Visitor then is prompted for typical registration data--name, email, etc.--and that data is stored in the newly created group table.
Any subsequent visitors associated with that group would click on "User Reg"
The visitor would be prompted for group name and password
If correct, then he would be prompted for typical reg data, to be stored in his group's table.
What I don't know how to do is implement the group authentication prior to allowing user registration. Can someone help me with that?
If the visitor is entering a group name and password, then you can authenticate the same way you are doing the users. You just need to first ask yourself if the group name needs to be unique or the group/password combination.
As for your idea to add a new table for each group, that is a bad idea. Imagine if you have 100 groups. Then you will have 100 tables just for groups. If you get up to 1000 groups, then you will have 1000 tables. Try managing that. It will get really frustrating really fast. Instead, what you should do is to first create a "Group" table with all the associated data (group name, password, etc). Then add a field to your User table that will hold the associated id from the Group table. That way, whenever you look up the user, you can easily check what group the user is in simply by joining the two tables rather than trying to figure out what table to look at as in your original plan.
What you want to end up with is a table for your users and another (single) table for your group information. The user table will have a foreign key field to link it to a group. When a user joins a group, you will enter a value in that field. Users not in groups will have a null value in that field. If users can create groups, they will simply be adding a new row to the groups table.
If your users can be in multiple groups, set up your tables like this.
USER
- id
- username
- password
- etc...
GROUP
- id
- name
- password (?)
- etc...
USER_GROUP_CR
- fk_user
- fk_group
The USER_GROUP_CR table is a "cross reference" or "link" table that will allow you to create a many to many relationship. This way you can have users in multiple groups without creating extra tables. When a user joins a group, add a row to the USER_GROUP_CR table with the id of the user and the id of the group. You can query this table to find out which groups a user belongs to, or to find out which users are in a group.
You should not create a new table for every group.