四个表上的复杂SQL查询无法获取想要的结果

时间:2013-10-02 21:40:13

标签: mysql sql database join

想象一下以下情况:公司的员工可以对任意问题(整数值)进行投票。

我有一个复杂的请求,我想要获取五个信息:

  1. 公司名称
  2. 每家公司的平均投票价值
  3. 员工人数
  4. 票数
  5. 参与(没有投票/没有雇员)
  6. SQL查询只能获取当前用户所使用的公司的投票。

    因此,我会访问四个不同的表,然后您会看到表声明的摘录:

    User
    - id
    
    Company
    - id
    - name
    
    Employment
    - user_id (FK User.id)
    - company_id (FK Company.id)
    
    Vote
    - company_name
    - vote_value
    - timestamp
    

    UserCompanyEmployment相关(n:m关系,但需要是额外的表格)。表Vote不能通过PK / FK关系连接,但它们可以通过公司名称(Company.name = Vote.company_name)与公司相关联。

    我设法通过以下SQL查询正确获取除员工数以外的所有信息:

    SELECT
        c.name AS company,
        AVG(v.vote_value) AS value,
        COUNT(e.user_id) AS employees,
        COUNT(f.face) AS votes,
        (COUNT(e.user_id) / COUNT(v.vote_value)) AS participation
    FROM Company c
    JOIN Employment e ON e.company_id = c.id
    JOIN User u ON u.id = e.user_id
    JOIN Vote v
        ON v.company_name = c.name
        AND YEAR(v.timestamp) = :year
        AND MONTH(v.timestamp) = :month
        AND DAY(v.timestamp) = :day
    WHERE u.id = :u_id
    GROUP BY v.company_name, e.company_id
    

    但是employee字段总是等于投票数,而不是获取正确数量的员工。 (因此participation值也是错误的。)

    有没有办法在没有子查询的一个查询中执行此 1 ?我需要更改什么才能使查询获取正确数量的员工?

    1 我正在使用Doctrine2并尝试避免子查询,因为Doctrine不支持它们。我只是不想将其纳入学说讨论。这就是我为什么把这个话题分解为SQL级别。

3 个答案:

答案 0 :(得分:1)

试试这个 - 它将投票计算为一个子查询,将雇员计算为另一个子查询。

SELECT c.name,
ce.employee_count,
cv.vote_count,
cv.vote_count / ce.employee_count,
cv.vote_value
FROM 
(select company, count(*) AS 'employee_count' 
FROM employment GROUP BY company) ce
INNER JOIN company c
ON c.id = ce.company
INNER  JOIN 
(select company, AVG(vote_value) AS 'vote_value', count(*) as 'vote_count'
FROM vote v GROUP BY company) cv
ON c.id = cv.company

答案 1 :(得分:1)

如果您想获取员工人数,那么问题是您只过滤了一名员工:

WHERE u.id = :u_id

其次,请记住,如果您想计算员工数量并且您已进入投票分组级别,那么当然您的行数将等于投票数量。所以你必须将其统计为@Przem ...提到:

COUNT(DISTINCT e.user_id) AS employees,

通过这种方式,您将对公司的员工进行唯一计算(为员工的所有投票取消重复的员工ID)。

正如你在评论中提到的那样:

  

它返回1作为员工计数

这是因为迫使1名员工获得多票的条件。 distinct将仅计算由where子句过滤的唯一1名员工,这就是您只得到1的原因。但是,这是正确的结果(基于您的过滤条件)。

select子句中添加子查询也可以获得正确的结果,但会牺牲性能。

答案 2 :(得分:0)

我认为定义的查询应该在计算员工数量时添加 DISTINCT 关键字:

SELECT
    c.name AS company,
    AVG(v.vote_value) AS value,
    COUNT(DISTINCT e.user_id) AS employees,
    COUNT(f.face) AS votes,
    (COUNT(DISTINCT e.user_id) / COUNT(v.vote_value)) AS participation
FROM Company c
JOIN Employment e ON e.company_id = c.id
JOIN User u ON u.id = e.user_id
JOIN Vote v
    ON v.company_name = c.name
    AND YEAR(v.timestamp) = :year
    AND MONTH(v.timestamp) = :month
    AND DAY(v.timestamp) = :day
GROUP BY v.company_name, e.company_id;

不确定是否可以在MySQL中使用。

编辑:正如@Mosty Mostacho指出的那样,u.id上的条件是问题,如果没有它,并且添加了DISTINCT关键字,查询将返回正确的结果并编辑上述查询。