SQL Server : database design - composite primary key - sql-server

I need your suggestion on how to implement SQL Server table relationships.
I have many customers, each holds a unique id (customerID)
each customer can have many categories associated (categoryID)
each customer can have many sub categories (subCategoryID) for
when a customer logs in I know its CustomerID, CategoryID and SubCategoryID.
customer plans in advance how many hours will work every week for the year to come (on december
2014 plans 52 weeks of 2015)
every day a customer reports if they worked or took a day off.
I thought of having a table called WeeklyPlanning with columns:
CustomerID, CategoryID, SubCategoryID, Year, WeekNumber, WorkingHoursPlan
and another table called DailyWorkingHours with columns:
Dates, WorkingHours
My questions:
I don't know how to combine these two tables together, use a compound key? (CustomerID, CategoryID, SubCategoryID, Year, WeekNumber) or maybe generate a unique PK in WeeklyPlanning that will be used as a FK in DailyWorkingHours?
I'm looking for the best way to implement this.
thanks

Do you really want to specify FIVE column's values for each JOIN between those two tables? That's what you'll have to do if you have a compound primary key made up from five columns - you need all those columns in your child table as well, and you need to always specify all five columns when doing a JOIN ..... ouch ......
If not - use a surrogate column in WeeklyPlanning (a WeeklyPlanningID INT IDENTITY(1,1)) to simplify your life significantly!

Related

How do I join two tables with a common column that is a primary in one and not in the other?

I'm pretty new to SQL and I'm trying to join two tables using a column that is a primary (and distinct) in one table but not primary (and could have multiple rows) in another. The code's below.
SELECT LEFT(CAST(dbo.PolicyDB.accountingmonth AS VARCHAR(4)),4) AS AccountingYear,
SUM(dbo.PolicyDB.EarnedPremium) AS EarnedPremium,
SUM(Loss.TotalPaidLoss) as TotalPaidLoss
FROM dbo.PolicyDB
INNER JOIN (
SELECT SUM(dbo.ClaimDB.losspaid + dbo.ClaimDB.expensepaid - dbo.ClaimDB.recovery) as TotalPaidLoss
FROM dbo.ClaimDB
GROUP BY accountingmonth
) Loss
ON dbo.PolicyDB.policykey = dbo.ClaimDB.policykey
GROUP BY LEFT(CAST(dbo.PolicyDB.accountingmonth AS VARCHAR(4)),4)
Basically, I am trying to create a table that will display three columns: Accounting Year, Earned Premium (for that year), and Total Paid Loss (for that year).
I have a couple problems. First, I don't know if I'm calling Loss.TotalPaidLoss properly. I don't know of any other ways to sum multiple fields into one when its database differs from the other.
Second, the column that is joining the two, Policy Key, is a primary (and unique) key in the Policy DB but not in the Claims DB (b/c multiple claims can come from one policy). When I run this code, I get this error message:
Msg 4104, Level 16, State 1, Line 11
The multi-part identifier "dbo.ClaimDB.policykey" could not be bound.
There are probably a bunch of errors in my code, but these two are my primary questions. If you spot other errors or improvements I can make, I'm all ears. I'd appreciate any help!
Your second table Loss in the JOIN is actually a derived(alias) table. You should be using dbo.PolicyDB.policykey = Loss.policykey. But this table right now does not have PolicyKey column. It needs to be :
SELECT LEFT(CAST(dbo.PolicyDB.accountingmonth AS VARCHAR(4)),4) AS AccountingYear,
SUM(dbo.PolicyDB.EarnedPremium) AS EarnedPremium,
SUM(Loss.TotalPaidLoss) as TotalPaidLoss
FROM dbo.PolicyDB
INNER JOIN (
SELECT SUM(losspaid + expensepaid - recovery) as TotalPaidLoss, PolicyKey
FROM dbo.ClaimDB
GROUP BY PolicyKey
) Loss
ON dbo.PolicyDB.policykey = Loss.policykey
GROUP BY LEFT(CAST(dbo.PolicyDB.accountingmonth AS VARCHAR(4)),4)
Also you don't need to rollup(group) the ClaimDB column by accounting month, I feel.

SQL Server 2008 Database Design

Background: In SQL Server, my database table only has three columns:
DataID (PK, bigint)
ProductName (Nchar20)
Price (float)
Every day it will automatically insert about 5000+ rows of data into this table. Later on this table may add more columns like AdjustedPrice (float), Discount (float)...
Question: I know I should probably make ProductName as FK to another table (ProductNameTable with ProductID (PK,int) and ProductName (Nchar), but what about the price (float)? Price are depends, could range to 100 - 1000, should I make it FK to another table or just leave it alone in the table?
Any advice from DBA? Thank you sooooo much.....
Yeah. No. Price is an atmic element. But my advice would be to get a copy of the Data Model Ressoure Book volume 1 - it discusses database schemata for pricing engines. A good read.

One to Many Database Table Relationship

I do have two tables from the database..
Consultation Table
-ConsultationNo -PK
-PatientNo -FK
-Diagnosis
-Etc...
VitalSign Table
-VitalSignNo -PK
-Weight
-Height
-HeartRate
-BloodPressure
-Etc
I need to join these two tables like this..
Consultation Table
-ConsultationNo -PK
-PatientNo -FK
**-VitalSignNo** -FK
-Diagnosis
-Etc...
But sometimes, my VitalSign Table will not accept any values, therefore the relationship between those two tables would not be enforced, what should I do?
Use an outer join like so...
Select * from Consultation
Left join VitalSign on (Consultation.ConsultationNo = vitalsign.ConsultationNo)
You will get all rows from consultation, and the matching rows from Vitalsign. When there are no rows in Vitalsign all those columns will come back null, but you will still get the consultation rows.
This might not be exactly right for your situation because the table structure in your question doesn't look complete. That, is you didn't have a foreign key in either table referencing the PK of the other.

Database tables: One-to-many of different types

Due to non-disclosure at my work, I have created an analogy of the situation. Please try to focus on the problem and not "Why don't you rename this table, m,erge those tables etc". Because the actual problem is much more complex.
Heres the deal,
Lets say I have a "Employee Pay Rise" record that has to be approved.
There is a table with single "Users".
There are tables that group Users together, forexample, "Managers", "Executives", "Payroll", "Finance". These groupings are different types with different properties.
When creating a "PayRise" record, the user who is creating the record also selects both a number of these groups (managers, executives etc) and/or single users who can 'approve' the pay rise.
What is the best way to relate a single "EmployeePayRise" record to 0 or more user records, and 0 or more of each of the groupings.
I would assume that the users are linked to the groups? If so in this case I would just link the employeePayRise record to one user that it applies to and the user that can approve. So basically you'd have two columns representing this. The EmployeePayRise.employeeId and EmployeePayRise.approvalById columns. If you need to get to groups, you'd join the EmployeePayRise.employeeId = Employee.id records. Keep it simple without over-complicating your design.
My first thought was to create a table that relates individual approvers to pay rise rows.
create table pay_rise_approvers (
pay_rise_id integer not null references some_other_pay_rise_table (pay_rise_id),
pay_rise_approver_id integer not null references users (user_id),
primary key (pay_rise_id, pay_rise_approver_id)
);
You can't have good foreign keys that reference managers sometimes, and reference payroll some other times. Users seems the logical target for the foreign key.
If the person creating the pay rise rows (not shown) chooses managers, then the user interface is responsible for inserting one row per manager into this table. That part's easy.
A person that appears in more than one group might be a problem. I can imagine a vice-president appearing in both "Executive" and "Finance" groups. I don't think that's particularly hard to handle, but it does require some forethought. Suppose the person who entered the data changed her mind, and decided to remove all the executives from the table. Should an executive who's also in finance be removed?
Another problem is that there's a pretty good chance that not every user should be allowed to approve a pay rise. I'd give some thought to that before implementing any solution.
I know it looks ugly but I think somethimes the solution can be to have the table_name in the table and a union query
create table approve_pay_rise (
rise_proposal varchar2(10) -- foreign key to payrise table
, approver varchar2(10) -- key of record in table named in other_table
, other_table varchar2(15) );
insert into approve_pay_rise values ('prop000001', 'e0009999', 'USERS');
insert into approve_pay_rise values ('prop000001', 'm0002200', 'MANAGERS');
Then either in code a case statement, repeated statements for each other_table value (select ... where other_table = '' .. select ... where other_table = '') or a union select.
I have to admit I shudder when I encounter it and I'll now go wash my hands after typing a recomendation to do it, but it works.
Sounds like you'd might need two tables ("ApprovalUsers" and "ApprovalGroups"). The SELECT statement(s) would be a UNION of UserIds from the "ApprovalUsers" and the UserIDs from any other groups of users that are the "ApprovalGroups" related to the PayRiseId.
SELECT UserID
INTO #TempApprovers
FROM ApprovalUsers
WHERE PayRiseId = 12345
IF EXISTS (SELECT GroupName FROM ApprovalGroups WHERE GroupName = "Executives" and PayRiseId = 12345)
BEGIN
SELECT UserID
INTO #TempApprovers
FROM Executives
END
....
EDIT: this would/could duplicate UserIds, so you would probably want to GROUP BY UserID (i.e. SELECT UserID FROM #TempApprovers GROUP BY UserID)

normalization of reservation database

hi im developing a online reservation of a event place my issue is in the module of ticketing if a client booked two functionroom in one ticket im not sure with my database if it is full normalized i just want to be sure please leave comment for database improvement
create table RESERVATIONS (
PK reservation_id
lname,
fname,
contact,
email,
date,
timeStart,
timeEnd
numGuest,
total)
create table FUNCTIONROOMS (
PK function_id,
FK functionroom_id,
FK reservation_id)
create table FUNCTIONROOMDETAILS(
PK functionroom_id,
functionName,
functionPrice,
functionStatus)
im planning for this query is my database normalized? or not
select functionRoom.functionRoom_id
from reservations, functionRoom
where reservation.reservation_id = functionRoom.reservation_id
and reservation_id = 'reservation_id'
Your tables doesn't seem to be normalized, there is no apparent primary key in Reservation.
Normalization is quite a topic, and there are several levels of normal forms, you can use just the ones you need.
And as Jim Garrison said in the comments queries can't be normalized, so your last question doesn't have a clear answer.

Resources