聚合查询取决于几个表

时间:2012-11-07 00:38:58

标签: mysql database-design

我想创建一个包含员工,工作,工资和项目信息的数据库

我想保留项目成本的信息(项目的实际价值和员工投资的天数)

对于员工和项目,每个员工通过PK约束在项目中有一个角色,并允许在将来添加新的角色类型(可能是“第三个”)。

    CREATE TABLE Employee(
      EmployeeID  INTEGER      NOT NULL PRIMARY KEY,
      Name        VARCHAR(30)  NOT NULL,
      Sex         CHAR(1)      NOT NULL,
      Address     VARCHAR(80)  NOT NULL,
      Security    VARCHAR(15)  NOT NULL,
      DeptID      INTEGER      NOT NULL,        
      JobID       INTEGER      NOT NULL
    );

    CREATE TABLE Departments  (
        DeptID   INTEGER     NOT NULL PRIMARY KEY,
        DeptName VARCHAR(30) NOT NULL
    );

    CREATE TABLE Jobs (
        JobID            INTEGER      NOT NULL PRIMARY KEY,
        JobName          VARCHAR(30)  NOT NULL,
        JobSalary        DOUBLE(15,3) NOT NULL default '0.000', 
        JobSalaryperDay  DOUBLE(15,3) NOT NULL default '0.000', 
        DeptID           INTEGER      NOT NULL
    );


    CREATE TABLE Project(
      ProjectID    INTEGER NOT NULL PRIMARY KEY,
      ProjectDesc   VARCHAR(200) NOT NULL,
      StartDate     DATE NOT NULL,
      EndDate       DATE NOT NULL, 
      DaysOfWork    INTEGER NOT NULL,
      NoEmployees   INTEGER NOT NULL,
      EstimatedCost DOUBLE(15,3) NOT NULL default '0.000', 
      RealCost      DOUBLE(15,3) NOT NULL default '0.000' 
    );


    CREATE TABLE `Project-Employee`(
      ProjectID    INTEGER NOT NULL,
      EmployeeID   INTEGER NOT NULL,
      Note         VARCHAR(200),
      DaysWork     INTEGER NOT NULL,
      CONSTRAINT fk_ProjectID  FOREIGN KEY (ProjectID)  REFERENCES Project(ProjectID),
      CONSTRAINT fk_EmployeeID FOREIGN KEY (EmployeeID) REFERENCES Employee(EmployeeID)
    );


INSERT INTO `Departments` VALUES (1, 'Outsourcing');
INSERT INTO `Departments` VALUES (2, 'Technician');
INSERT INTO `Departments` VALUES (3, 'Administrative');

INSERT INTO `Jobs` VALUES (1, 'welder'    ,500.550,16.7 ,2);
INSERT INTO `Jobs` VALUES (2, 'turner'    ,500.100,16.67,2);
INSERT INTO `Jobs` VALUES (3, 'assistant' ,650.100,21.67,2);
INSERT INTO `Jobs` VALUES (4, 'supervisor',800.909,26.70,3);
INSERT INTO `Jobs` VALUES (5, 'manager'   ,920.345,30.68,3);
INSERT INTO `Jobs` VALUES (6, 'counter'   ,520.324,17.35,1);



INSERT INTO `Employee` VALUES (10, 'Joe',  'M', 'Anywhere', '927318344', 1, 3);
INSERT INTO `Employee` VALUES (20, 'Moe',  'M', 'Anywhere', '827318322', 2, 3);
INSERT INTO `Employee` VALUES (30, 'Jack', 'M', 'Anywhere', '927418343', 3, 4);
INSERT INTO `Employee` VALUES (40, 'Marge','F', 'Evererre', '127347645', 1, 6);
INSERT INTO `Employee` VALUES (50, 'Greg' ,'M', 'Portland', '134547633', 3, 5);


INSERT INTO `Project` VALUES (1, 'The very first', '2008-7-04' , '2008-7-24' , 20, 5, 3000.50, 2500.00);
INSERT INTO `Project` VALUES (2, 'Second one pro', '2008-8-01' , '2008-8-30' , 30, 5, 6000.40, 6100.40);


INSERT INTO `Project-Employee` VALUES (1, 10, 'Worked all days'    , 20);
INSERT INTO `Project-Employee` VALUES (1, 20, 'Worked just in defs', 11);
INSERT INTO `Project-Employee` VALUES (1, 30, 'Worked just in defs', 17);
INSERT INTO `Project-Employee` VALUES (1, 40, 'Contability '       , 8);
INSERT INTO `Project-Employee` VALUES (1, 50, 'Managed the project', 8);

因此,为了获得项目成本的总额并将其用于未来的工作报价,我将在聚合查询中将每个员工的每个工作的工作日总和。

如果知道参与特定项目的员工知道他们工作所产生的成本,那么在所有工作日内总结一下这个查询是什么?是否可以通过此设计了解这一点?

因此,假设我知道在项目1中,有5名员工参与其中,而我从其他表“工作”中知道我每天要支付的工资

我正在进行一些查询here with sqlfiddle

更新

 CREATE TABLE `Sexes` (
   Sex char(1) primary key
 );
 INSERT INTO Sexes values ('M');
 INSERT INTO Sexes values ('F');

CREATE TABLE `Employee`(
  EmployeeID  INTEGER      NOT NULL PRIMARY KEY,
  Name        VARCHAR(130)  NOT NULL,
  Sex         CHAR(1)      NOT NULL,
  Address     VARCHAR(380)  NOT NULL,
  Security    VARCHAR(15)  NOT NULL,
  FOREIGN KEY (Sex) references Sexes (Sex),
  CONSTRAINT `uc_EmployeeInfo` UNIQUE (`EmployeeID`,`Name`,`Security`)           
);

CREATE TABLE `Department`  (
  DeptID   INTEGER     NOT NULL PRIMARY KEY,
  DeptName VARCHAR(30) NOT NULL,
  CONSTRAINT `uc_DeptName` UNIQUE (`DeptID`,`DeptName`)
);

CREATE TABLE `Dept-Employee`(
  EmployeeID   INTEGER NOT NULL,          
  DeptID       INTEGER NOT NULL,     
  CONSTRAINT fk_DeptID     FOREIGN KEY (DeptID)     REFERENCES `Department`(DeptID),
  CONSTRAINT fk_EmployeeID FOREIGN KEY (EmployeeID) REFERENCES `Employee`(EmployeeID)
);

 CREATE TABLE `Dept-Manager`(
  EmployeeID   INTEGER NOT NULL,          
  DeptID       INTEGER NOT NULL,
  CONSTRAINT fk_DeptIDs     FOREIGN KEY (DeptID)     REFERENCES `Department`(DeptID),
  CONSTRAINT fk_EmployeeIDs FOREIGN KEY (EmployeeID) REFERENCES `Employee`(EmployeeID)
);

CREATE TABLE `Jobs` (
  JobID            INTEGER      NOT NULL PRIMARY KEY,
  JobName          VARCHAR(30)  NOT NULL,
  JobSalary        DECIMAL(7,3) NOT NULL default '0000.000', 
  JobSalaryperDay  DECIMAL(7,3) NOT NULL default '0000.000', 
  CONSTRAINT `uc_jobs` UNIQUE (`JobID`,`JobName`)
);

CREATE TABLE `Jobs-Employee`(
  EmployeeID   INTEGER NOT NULL,
  JobID        INTEGER NOT NULL,
  CONSTRAINT fk_JobIDs       FOREIGN KEY (JobID)      REFERENCES `Jobs`(JobID),
  CONSTRAINT fk_EmployeeIDss FOREIGN KEY (EmployeeID) REFERENCES `Employee`(EmployeeID)
);

CREATE TABLE `Project`(
  ProjectID     INTEGER NOT NULL PRIMARY KEY,
  ProjectName   VARCHAR(200) NOT NULL,
  StartDate     DATE    NOT NULL,
  DaysOfWork    INTEGER NOT NULL,
  NoEmployees   INTEGER NOT NULL,
  EstimatedCost DECIMAL(9,3) NOT NULL default '000000.000', 
  RealCost      DECIMAL(9,3) NOT NULL default '000000.000', 
  CONSTRAINT `uc_project` UNIQUE (`ProjectID`,`ProjectName`)           
);

CREATE TABLE `Project-Employee`(
  ProjectID    INTEGER NOT NULL,
  EmployeeID   INTEGER NOT NULL,
  Note         VARCHAR(200),
  DaysWork     INTEGER NOT NULL,
  CONSTRAINT fk_ProjectIDsss  FOREIGN KEY (ProjectID)  REFERENCES `Project`(ProjectID),
  CONSTRAINT fk_EmployeeIDsss FOREIGN KEY (EmployeeID) REFERENCES `Employee`(EmployeeID)
);


    INSERT INTO `Department` VALUES (1, 'Outsourcing');
    INSERT INTO `Department` VALUES (2, 'Technician');
    INSERT INTO `Department` VALUES (3, 'Administrative');

    INSERT INTO `Jobs` VALUES (1, 'welder'    ,500.550, 16.7 );
    INSERT INTO `Jobs` VALUES (2, 'turner'    ,500.100, 16.67);
    INSERT INTO `Jobs` VALUES (3, 'assistant' ,650.100, 21.67);
    INSERT INTO `Jobs` VALUES (4, 'supervisor',800.909, 26.70);
    INSERT INTO `Jobs` VALUES (5, 'manager'   ,920.345, 30.68);
    INSERT INTO `Jobs` VALUES (6, 'counter'   ,520.324, 17.35);

    INSERT INTO `Employee` VALUES (10, 'Joe',  'M', 'Joewhere', '927318344');
    INSERT INTO `Employee` VALUES (20, 'Moe',  'M', 'Moewhere', '827318322');
    INSERT INTO `Employee` VALUES (30, 'Jack', 'M', 'Jaswhere', '927418343');
    INSERT INTO `Employee` VALUES (40, 'Marge','F', 'Evererre', '127347645');
    INSERT INTO `Employee` VALUES (50, 'Greg' ,'M', 'Portland', '134547633');

    INSERT INTO `Dept-Employee`  VALUES (10,1);
    INSERT INTO `Dept-Employee`  VALUES (20,2);
    INSERT INTO `Dept-Employee`  VALUES (30,3);
    INSERT INTO `Dept-Employee`  VALUES (40,1);
    INSERT INTO `Dept-Employee`  VALUES (50,3);

    INSERT INTO `Jobs-Employee`  VALUES (10,3);
    INSERT INTO `Jobs-Employee`  VALUES (20,3);
    INSERT INTO `Jobs-Employee`  VALUES (30,4);
    INSERT INTO `Jobs-Employee`  VALUES (40,6);
    INSERT INTO `Jobs-Employee`  VALUES (50,5);

    INSERT INTO `Project` VALUES (1, 'The very first', '2008-7-04' , 20, 5, 3000.50, 2500.00);
    INSERT INTO `Project` VALUES (2, 'Second one pro', '2008-8-01' , 30, 5, 6000.40, 6100.40);

    INSERT INTO `Project-Employee` VALUES (1, 10, 'Worked all days'    , 20);
    INSERT INTO `Project-Employee` VALUES (1, 20, 'Worked just in defs', 11);
    INSERT INTO `Project-Employee` VALUES (1, 30, 'Worked just in defs', 17);
    INSERT INTO `Project-Employee` VALUES (1, 40, 'Contability '       , 8);
    INSERT INTO `Project-Employee` VALUES (1, 50, 'Managed the project', 8);

对于新结构我做了这个

CREATE VIEW `Emp-Job` as
SELECT e.*,j.jobID  
FROM  Employee e,`Jobs-Employee` j
WHERE e.EmployeeID = j.EmployeeID;



CREATE VIEW `employee_pay` as
select e.*, j.jobname, j.jobsalary, j.jobsalaryperday
from `Emp-Job` e
inner join `Jobs` j
        on e.JobID = j.JobID;

create view project_pay as 
select pe.projectid, pe.employeeid, pe.dayswork,
       e.jobsalaryperday, (e.jobsalaryperday * dayswork) as total_salary
from `Project-Employee` pe
inner join `employee_pay` e
        on e.employeeid = pe.employeeid

1 个答案:

答案 0 :(得分:2)

问题末尾的数据似乎与INSERT语句中的数据不匹配。

你听说过“分而治之”吗?这是使用它的好时机。这就是我要做的事。

create view employee_pay as
select e.*, j.jobname, j.jobsalary, j.jobsalaryperday
from employee e
inner join jobs j on e.jobid = j.jobid

create view project_pay as 
select pe.projectid, pe.employeeid, pe.dayswork,
       e.jobsalaryperday, (e.jobsalaryperday * dayswork) as total_salary
from project_employee pe
inner join employee_pay e
        on e.employeeid = pe.employeeid

,因为我希望这些视图通常很有用。 (特别是对于调试。)创建这些视图后,项目的总计很简单。

select projectid, sum(total_salary) as total_salaries
from project_pay
group by projectid

projectid  total_salaries
--
1          1509.91

真的不想用DOUBLE赚钱。 Use DECIMAL instead


使用此查询来理清我的总和与您的总和不匹配的原因。

select p.*, e.name
from project_pay p
inner join employee e on e.employeeid = p.employeeid;

projectid  employeeid  dayswork  jobsalaryperday  total_salary  name
1          10          20        21.67            433.4         Joe
1          20          11        21.67            238.37        Moe
1          30          17        26.7             453.9         Jack
1          40           8        17.35            138.8         Marge
1          50           8        30.68            245.44        Greg

反模式

身份破碎

每当你看到像这样的表时

CREATE TABLE Departments  (
    DeptID   INTEGER     NOT NULL PRIMARY KEY,
    DeptName VARCHAR(30) NOT NULL
);

你应该假设它的结构是错误的,并深入挖掘。 (在证明无辜之前,它被认为是有罪的。)你寻找的反模式

  • 整数作为人工主键,以及
  • 其他唯一约束。

这样的表允许复制真实数据,从而消除了人工密钥的有用性。

DeptID  DeptName
--
1       Wibble
2       Wibble
...
175     Wibble

这样的表也允许多个外键引用。这意味着一些外键可能引用Wibble(DeptID = 1),一些可能引用Wibble(DeptID = 175),依此类推。

要解决此问题,请在DeptName上添加UNIQUE约束。

缺少外键引用

每当你看到像这样的表时

CREATE TABLE Employee(
  EmployeeID  INTEGER      NOT NULL PRIMARY KEY,
  Name        VARCHAR(30)  NOT NULL,
  ...
  DeptID      INTEGER      NOT NULL,        
  JobID       INTEGER      NOT NULL
);

你应该假设它的结构是错误的,并深入挖掘。 (再一次,在被证明是无辜之前,它被认为是有罪的。)你寻找的反模式

  • 其他表格中的ID号码以及
  • 没有引用这些表的外键约束。

要解决此问题,请为DeptID和JobID添加外键约束。在MySQL上,确保你也使用INNODB引擎。 (从MySQL 5.6开始,MyISAM still won't enforce foreign key constraints,但如果你编写它们就不会给你一个错误或警告。它们被解析并被忽略。)

如果你从另一个dbms来到MySQL,你会惊讶地发现MySQL不支持内联外键引用语法。这意味着你不能写这个。

DeptID integer not null references Departments (DeptID)

相反,您必须在CREATE TABLE语句中编写单独的外键子句。 (或使用单独的ALTER TABLE语句声明FK引用。)

DeptID integer not null,
foreign key (DeptID) references Departments (DeptID)

this page搜索“inline ref”,但请阅读整篇文章。

缺少CHECK()约束

MySQL不强制执行CHECK()约束,因此对于请求CHECK()约束的列,您需要一个表和一个外键引用。当你看到像这样的结构时

CREATE TABLE Employee(
  EmployeeID  INTEGER      NOT NULL PRIMARY KEY,
  Name        VARCHAR(30)  NOT NULL,
  Sex         CHAR(1)      NOT NULL,

CHOOK()约束中的“Sex”列。

CREATE TABLE Employee(
  EmployeeID  INTEGER      NOT NULL PRIMARY KEY,
  Name        VARCHAR(30)  NOT NULL,
  Sex         CHAR(1)      NOT NULL CHECK( Sex IN ('M', 'F')),

但是MySQL没有强制执行CHECK()约束,所以你需要另一个表和一个外键引用。

create table sexes (
  sex char(1) primary key
);
insert into sexes values ('M');
insert into sexes values ('F');

CREATE TABLE Employee(
  EmployeeID  INTEGER      NOT NULL PRIMARY KEY,
  Name        VARCHAR(30)  NOT NULL,
  Sex         CHAR(1)      NOT NULL,
  ...
  foreign key (Sex) references Sexes (Sex)

我会考虑大多数这些列的CHECK()约束。有些可以实现为具有外键引用的表。

  • Employee.Security
  • Jobs.JobSalary
  • Jobs.JobSalaryperDay
  • Project.DaysOfWork
  • Project.NoEmployees
  • Project.EstimatedCost
  • Project.RealCost
  • Project_Employee.DaysWork

使用浮点数据类型

不要那样做。浮点数是有用的近似值,但它们仍然是近似值。请改用DECIMAL。