Database schema for Sales Commissions - sql

I'm trying to create a database with table titles which contains different titles, code(short code for the name) and commission of that title on other titles for instance.
I have a table named Title
Id Name Code CommissionOnA CommissionOnEng
1 Admin A 0 15
2 Engineer Eng 1 0
Now Is it good to have table schema like this, as the titles will change and can be inserted, updated or deleted dynamically. So with my current approach I have to alter table and add another column to it, in order to add commission for new title.
Is there any better way to do it, considering in mind that this also support multilevel sale heirarchy. Schema for any database is fine, but for MySql is preferred.
The Scenerio is, that the form where user creates a new title, dynamically renders all the titles that exist in the table with the textbox, so that when user creates a new title, he should be able to add commissions corresponding to other titles for the new title.
for instance if user creates a new Title name "Consultant" with code "c", he should see textboxes for Admin, Engineer, so that when user saves it, a row in the table gets created which has following data
Id Name Code CommissionOnA CommissionOnEng CommissionOnC
1 Admin A 0 15 0
2 Engineer Eng 1 0 0
3 Consultant C 12 5 0
Now I have another table called Employees
Id Name Title ManagerId
1 Rob 1 Null
2 Kate 2 1
3 Eli 3 2
4 Al 2 3
Now when Ido recursion, each time a junior get sale, a commission should be transfered to his manager as well as manager of his manager based on the commission specified in the title table.
So, when Al sells something, than Eli should get commission of 5 as, title of Eli is Consultant and Eli is boss of Al, so Employee with title Consultant(3) get commission of 5, if Employee with title Engineer(2) sells something.

It's better to normalise your table schemas so you don't need to add new columns instead put those related columns into their own table and then join these records via a foreign key.
For example, create a new table named commissions, then have a column for its unique ID, the ID that relates to the titles table and the commission amount:
commissions
----------------------------
id (INT, NOT NULL, Primary Key)
titles_id (INT, NOT NULL)
amount (INT, NOT NULL, DEFAULT=0)
and the data would look like:
id titles_id amount
1 1 15
2 2 1

Related

How to join with a table on a non unique column without getting redundant results?

Say I have two tables named Customers and Banks.
Customers has Id(PK), Name and BankCode
Banks has Id(PK), Name and Code
BankCode column in Customers table is a loose reference to Code column in Banks table. Code is not a foreign key so there are multiple records with the same Code.
Sample data is like this:
Persons:
Id
Name
BankCode
1
Jack
2
2
Jane
2
3
John
5
Banks:
Id
Name
Code
1
National
2
2
National Subsidiary
2
3
GNB
3
4
Global Banking
5
I need to get a list of persons with their bank name attached, I tried simply joining tables like this:
SELECT P.Id, P.Name, P.BankCode, B.Name
FROM Persons P
JOIN Banks B
ON P.BankCode = B.Code
But this query results in redundant records for persons whose bank code isn't unique. In this case Jack and Jane will each have two similar records with different bank names.
Since the banks with the same code are a family and have similar names, how can I manipulate the query to result only one record for each person (only use one bank name and ignore others)?
If you don't want to fix the design of your tables,
than the only way I can think of is to show all banks with that code for each user,
like this
select p.id,
p.Name,
( select string_agg(b.Name, ', ')
from Banks b
where b.BankCode = p.BankCode
) as Banks
from Persons p
This will look like this
id
Name
Banks
1
Jack
National, National Subsidiary
2
Jane
National, National Subsidiary
3
John
Global Banking
See a working DBFiddle here

How do I make a query for if value exists in row add a value to another field?

I have a database on access and I want to add a value to a column at the end of each row based on which hospital they are in. This is a separate value. For example - the hospital called "St. James Hospital" has the id of "3" in a separate field. How do I do this using a query rather than manually going through a whole database?
example here
Not the best solution, but you can do something like this:
create table new_table as
select id, case when hospital="St. James Hospital" then 3 else null
from old_table
Or, the better option would be to create a table with the columns hospital_name and hospital_id. You can then create a foreign key relationship that will create the mapping for you, and enforce data integrity. A join across the two tables will produce what you want.
Read about this here:
http://net.tutsplus.com/tutorials/databases/sql-for-beginners-part-3-database-relationships/
The answer to your question is a JOIN+UPDATE. I am fairly sure if you looked up you would find the below link.
Access DB update one table with value from another
You could do this:
update yourTable
set yourFinalColumnWhateverItsNameIs = {your desired value}
where someColumn = 3
Every row in the table that has a 3 in the someColumn column will then have that final column set to your desired value.
If this isn't what you want, please make your question clearer. Are you trying to put the name of the hospital into this table? If so, that is not a good idea and there are better ways to accomplish that.
Furthermore, if every row with a certain value (3) gets this value, you could simply add it to the other (i.e. Hospitals) table. No need to repeat it everywhere in the table that points back to the Hospitals table.
P.S. Here's an example of what I meant:
Let's say you have two tables
HOSPITALS
id
name
city
state
BIRTHS
id
hospitalid
babysname
gender
mothersname
fathername
You could get a baby's city of birth without having to include the City column in the Births table, simply by joining the tables on hospitals.id = births.hospitalid.
After examining your ACCDB file, I suggest you consider setting up the tables differently.
Table Health_Professionals:
ID First Name Second Name Position hospital_id
1 John Doe PI 2
2 Joe Smith Co-PI 1
3 Sarah Johnson Nurse 3
Table Hospitals:
hospital_id Hospital
1 Beaumont
2 St James
3 Letterkenny Hosptial
A key point is to avoid storing both the hospital ID and name in the Health_Professionals table. Store only the ID. When you need to see the name, use the hospital ID to join with the Hospitals table and get the name from there.
A useful side effect of this design is that if anyone ever misspells a hospital name, eg "Hosptial", you need correct that error in only one place. Same holds true whenever a hospital is intentionally renamed.
Based on those tables, the query below returns this result set.
ID Second Name First Name Position hospital_id Hospital
1 Doe John PI 2 St James
3 Johnson Sarah Nurse 3 Letterkenny Hosptial
2 Smith Joe Co-PI 1 Beaumont
SELECT
hp.ID,
hp.[Second Name],
hp.[First Name],
hp.Position,
hp.hospital_id,
h.Hospital
FROM
Health_Professionals AS hp
INNER JOIN Hospitals AS h
ON hp.hospital_id = h.hospital_id
ORDER BY
hp.[Second Name],
hp.[First Name];

How to change values of foreign keys in postgresql?

Let's say I have two tables: Customer and City. There are many Customers that live in the same City. The cities have an uid that is primary key. The customers have a foreign key reference to their respective city via Customer.city_uid.
I have to swap two City.uids with one another for external reasons. But the customers should stay attached to their cities. Therefore it is necessary to swap the Customer.city_uids as well. So I thought I first swap the City.uids and then change the Customer.city_uids accordingliy via an UPDATE-statement. Unfortunately, I can not do that since these uids are referenced from the Customer-table and PostgreSQL prevents me from doing that.
Is there an easy way of swapping the two City.uids with one another as well as the Customer.city_uids?
One solution could be:
BEGIN;
1. Drop foreign key
2. Make update
3. Create foreign key
COMMIT;
Or:
BEGIN;
1. Insert "new" correct information
2. Remove outdated information
COMMIT;
My instinct is to recommend not trying to change the city table's id field. But there is lot of information missing here. So it really is a feeling rather than a definitive point of view.
Instead, I would swap the values in the other fields of the city table. For example, change the name of city1 to city2's name, and vice-versa.
For example:
OLD TABLE NEW TABLE
id | name | population id | name | population
------------------------- -------------------------
1 | ABerg | 123456 1 | BBerg | 654321
2 | BBerg | 654321 2 | ABerg | 123456
3 | CBerg | 333333 3 | CBerg | 333333
(The ID was not touched, but the other values were swapped. Functionally the same as swapping the IDs, but with 'softer touch' queries that don't need to make any changes to table constraints, etc.)
Then, in your associated tables, you can do...
UPDATE
Customer
SET
city_uid = CASE WHEN city_uid = 1 THEN 2 ELSE 1 END
WHERE
city_uid IN (1,2)
But then, do you have other tables that reference city_uid? And if so, is it feasible for you to repeat that update on all those tables?
You could create two temporary cities.
You would have:
City 1
City 2
City Temp 1
City Temp 2
Then, you could do the follow:
Update all Customer UIDs from City 1 to City Temp 1.
Update all Customer UIDs from City 2 to City Temp 2.
Swap City 1 and 2 UIDs
Move all Customers back from City Temp 1 to City 1.
Move all Customers back from City Temp 2 to City 2.
Delete the temporally cities.
You can also add an ON UPDATE CASCADE clause to the parent table's CREATE TABLE statement, as described here:
How to do a cascading update?

SQL for checkboxes with a many-to-many relationship

I have three tables.
Directors:
Directors
ID
First Name
Last Name
Films:
Films
Film ID
Title
Total
Directors-to-Films
Director-to-Films
Director ID
Film ID
The Directors-to-Films stores the ids like this:
Director ID Film ID
1 1
1 2
1 3
1 4
The films I list with checkboxes.
How do I do an SQL update so that the table looks like:
Director ID Film ID
1 1
1 3
(i.e. Films "2" and "4" are removed) OR
Director ID Film ID
1 1
1 2
1 3
1 4
1 5
(i.e. Film "5" is added to Director "1")?
Unless I'm missing something, the SQL you're looking for is just a delete and an insert:
delete Directors_to_Films where Director_ID = 1 and Film_ID in (2,4);
insert into Directors_to_Films (Director_ID, Film_ID) values (1,5);
This assumes that when you're creating the UI, that you are fetching the appropriate IDs and associating them to the controls.
To clarify the last statement: If I understand correctly, you're displaying the film, then a list of directors with check boxes next to their names. The user can check one or more of the boxes. if this is correct, then, presumably, you are retrieving the list of directors from the database. At the same time you should be retrieving the associated ID and storing it in a property of the check box. When it comes time to update the database, you ask the check-box control for that value to figure out which row of the database you're updating.

sql insert and update question..multiple queries in one statement

I have a table called auctions, which has various columns such as username, auction id(the primary key), firstname, lastname, location etc, as well as a category column. The category column is blank by default, unless it is filled in for a particular record by a user.
I have made a new users table, which has username and category columns, as well as aditional fields which will be completed by user input.
I would like to know if it is possible when updating a record in the auctions table to have a category, to insert the username and category from that record into the users table as long as the username is not already present in the table.
For example, if I have the following tables:
auctions
auctionid username firstname lastname category
------------------------------------------------------------------------
1 zerocool john henry
2 fredflint fred smith
3 azazal mike cutter
Then, upon updating the second record to have a catagory like so:
2 fredflintsoner fred smith shoes
The resulting users table should be:
users
username shoes pants belts misc1 misc2
--------------------------------------------------
fredflint true
With no record have existed previously.
If additional auctions exist with the same username in the auctions table, such as:
7 fredflint fred smith belts
Then even if this auction is added to the category, a new record should not be inserted for the users table, as the username is already , however it should be updated as necessary, resulting in:
username shoes pants belts misc1 misc2
--------------------------------------------------
fredflint true true
What you are looking for is known as a TRIGGER. You can specify something to run after every insert/update in the auctions table and then determine what to do to the users table.
A couple of questions come to mind. The first is, your user table looks denormalized. What happens when you add a new category? Consider a user table in the form of:
id username category
Where you have multiple rows if a user has multiple categories:
1 fredflint shoes
2 fredflint pants
....
The second question I have is, why do you need a user table at all? It looks like all the information in the user table is already stored in the auction table! You can retrieve the user table simply by:
select distinct username, category
from auctions
If you need the separate table, an option to manually update the table when you create a new auction. I'd do it like this (I know just enough about triggers to avoid them):
1 - Make sure there's a row for this user
if not exists (select * from users where username = 'fredflint')
insert into users (username) values ('fredflint')
2 - Make sure he the shoe category
if not exists (select * from users where username = 'fredflint' and shoes = 1)
update users set shoes = 1 where username = 'fredflint'