Группировка по + присоединяется - PullRequest
1 голос
/ 17 июня 2011

Привет, у меня проблемы с использованием Group By и соединения между 3 таблицами.

У меня есть таблица проекта с различными полями и полями кода проекта. Затем у меня есть таблица счетов и таблица часов, и каждая может иметь несколько строк на проект. Обе эти таблицы также имеют код проекта.

Два значения SUM не рассчитаны правильно, и я действительно изо всех сил пытаюсь понять, в чем проблема.

Вот sql, который я использую:

SELECT  dbo.project.projectcode, 
        dbo.project.client, 
        dbo.project.project, 
        dbo.project.budget, 
        dbo.project.budget * 80 AS value, 
        SUM(dbo.harvest.hours) AS hourslogged, 
        SUM(dbo.salesforce.value) AS invoiced
FROM  dbo.salesforce 
    RIGHT OUTER JOIN dbo.project 
        ON dbo.salesforce.projectcode = dbo.project.projectcode 
    LEFT OUTER JOIN dbo.harvest 
        ON dbo.project.projectcode = dbo.harvest.projectcode
GROUP BY    dbo.project.projectcode, 
            dbo.salesforce.projectcode, 
            dbo.harvest.projectcode, 
            dbo.project.project, 
            dbo.project.client, 
            dbo.project.budget

Любая помощь или советы по этому вопросу будет принята с благодарностью!

Ответы [ 2 ]

1 голос
/ 18 июня 2011

Всякий раз, когда в каждой из двух таблиц dbo.salesforce и dbo.harvest имеется более одного совпадения для каждого projectcode, возникает мини- декартово произведение .Вот простая иллюстрация.Предположим, есть таблицы A и B, например:

  • Таблица A:

    AID  AVALUE
    ---  -------
    1    ValueA1
    2    ValueA2
    
  • Таблица B:

    BID  BVALUE   AID
    ---  -------  ---
    1    ValueB1  1
    2    ValueB2  1
    3    ValueB3  2
    

Теперь, если мы выполнили это объединение:

SELECT * FROM A JOIN B ON A.AID = B.AID

результат будет:

AID  AVALUE   BID  BVALUE   AID
---  -------  ---  -------  ---
1    ValueA1  1    ValueB1  1
1    ValueA1  2    ValueB2  1
2    ValueA2  3    ValueB3  2

Введите таблицу C:

CID  CVALUE   AID
---  -------  ---
1    ValueC1  1
2    ValueC2  1
3    ValueC3  1

И соединение теперь таково:

SELECT * FROM A JOIN B ON A.AID = B.AID JOIN C ON A.AID = C.AID

Каким будет результат?Здесь:

AID  AVALUE   BID  BVALUE   AID  CID  CVALUE   AID
---  -------  ---  -------  ---  ---  -------  ---
1    ValueA1  1    ValueB1  1    1    ValueC1  1
1    ValueA1  1    ValueB1  1    2    ValueC2  1
1    ValueA1  1    ValueB1  1    3    ValueC3  1
1    ValueA1  2    ValueB2  1    1    ValueC3  1
1    ValueA1  2    ValueB2  1    2    ValueC3  1
1    ValueA1  2    ValueB2  1    3    ValueC3  1

Как видите, каждое совпадение с B повторяется три раза, сколько совпадений получило C.И, аналогично, каждое совпадение из C повторяется дважды, потому что именно столько совпадений есть в B.Самым «счастливым», конечно же, является строка из A, потому что она повторяется 2 × 3 = 6 раз.Это декартово соединение для вас.И это именно то, что происходит и в вашем случае.

Не уверен, считается ли это типичным, но в таких случаях я часто группирую каждую таблицу отдельно по объединяющим выражениям, а затем объединяю результирующие наборы.Ваш запрос будет выглядеть так:

SELECT
  p.projectcode, 
  p.client, 
  p.project, 
  p.budget, 
  p.budget * 80 AS value, 
  h.hourslogged, 
  s.invoiced
FROM dbo.project p
  LEFT JOIN (
    SELECT
      projectcode,
      SUM(dbo.salesforce.value) AS invoiced
    FROM dbo.salesforce
    GROUP BY projectcode
  ) s ON p.projectcode = s.projectcode
  LEFT JOIN (
    SELECT
      projectcode,
      SUM(dbo.harvest.hours) AS hourslogged
    FROM dbo.harvest 
    GROUP BY projectcode
  ) h ON p.projectcode = h.projectcode
0 голосов
/ 17 июня 2011

Я бы посоветовал не смешивать правое и левое внешнее соединение. Ваш центральный стол - Project, поэтому сначала используйте его.

SELECT  dbo.project.projectcode, 
        dbo.project.client, 
        dbo.project.project, 
        dbo.project.budget, 
        dbo.project.budget * 80 AS value, 
        SUM(dbo.harvest.hours) AS hourslogged, 
        SUM(dbo.salesforce.value) AS invoiced
FROM    dbo.project      
            LEFT OUTER JOIN dbo.salesforce
                ON dbo.salesforce.projectcode = dbo.project.projectcode 
            LEFT OUTER JOIN dbo.harvest 
                ON dbo.project.projectcode = dbo.harvest.projectcode
GROUP BY    dbo.project.projectcode, 
            dbo.project.project, 
            dbo.project.client, 
            dbo.project.budget

Но ошибка исходит от GROUP BY. Вам не нужно группировать по двум таблицам, по которым вы производите агрегат, иначе ваш агрегат не будет хорошим!

...