Подсчет данных из нескольких таблиц с использованием SUM - PullRequest
2 голосов
/ 24 сентября 2011

У меня есть таблица с позициями

tbl_positions
   id position
    1 Driver
    2 Lobby
    3 Support
    4 Constructor 

, а в другой таблице у меня есть пользователи

РЕДАКТИРОВАТЬ:

   tbl_workers
      id   name   position position2 status
       1   John   2        3         4
       2   Mike   3        2         2
       3   Kate   2        0         3
       4   Andy   1        0         0

я делаю запрос позиций

SELECT p.id, 
    p.position, 
    SUM(CASE w.Status WHEN 2 THEN 1 ELSE 0 END)  AS booked,
    SUM(CASE w.Status WHEN 3 THEN 1 ELSE 0 END)  AS placed
  FROM  tbl_positions AS p LEFT JOIN tbl_workers AS w 
      ON w.position=p.id
GROUP BY p.id, p.position

Мне нужен такой вывод в одном запросе.

Position    booked placed
Driver        0       0
Lobby         1       2
Support       0       2
Constructor   0       0

Мне нужно оценить оба поля positon1 и position2 вместо одного.Я думаю, что это легко изменить, но я не могу найти правильное решение, пожалуйста, помогите.

РЕДАКТИРОВАТЬ: Добавлен статус 4

Ответы [ 3 ]

1 голос
/ 24 сентября 2011

Вместо присоединения к tbl_workers вы можете присоединиться к его непивотному варианту, где position и position2 будут в одном столбце, но в разных строках.

Вот как может выглядеть открепление:

SELECT
  w.id,
  w.name,
  CASE x.pos WHEN 1 THEN w.position ELSE w.position2 END AS position,
  w.status
FROM tbl_workers AS w
  CROSS JOIN (SELECT 1 AS pos UNION ALL SELECT 2) AS x

Вот весь запрос, который в основном является вашим исходным запросом с указанным выше запросом, заменяющим таблицу tbl_workers:

SELECT p.id, 
  p.position, 
  SUM(CASE w.Status WHEN 2 THEN 1 ELSE 0 END)  AS booked,
  SUM(CASE w.Status WHEN 3 THEN 1 ELSE 0 END)  AS placed
FROM tbl_positions AS p
  LEFT JOIN (
    SELECT
      w.id,
      w.name,
      CASE x.pos WHEN 1 THEN w.position ELSE w.position2 END AS position,
      w.status
    FROM tbl_workers AS w
      CROSS JOIN (SELECT 1 AS pos UNION ALL SELECT 2) AS x
  ) AS w 
  ON w.position=p.id
GROUP BY p.id, p.position

UPDATE

Это модифицированный скрипт согласно дополнительному запросу в комментариях:

SELECT p.id, 
  p.position, 
  SUM(CASE w.Status WHEN 2 THEN 1 ELSE 0 END)  AS booked,
  SUM(CASE w.Status WHEN 3 THEN 1 ELSE 0 END)  AS placed
FROM tbl_positions AS p
  LEFT JOIN (
    SELECT
      w.id,
      w.name,
      CASE x.pos WHEN 1 THEN w.position ELSE w.position2 END AS position,
      CASE w.status
        WHEN 4 THEN CASE x.pos WHEN 1 THEN 3 ELSE 2 END
        ELSE w.status
      END AS status
    FROM tbl_workers AS w
      CROSS JOIN (SELECT 1 AS pos UNION ALL SELECT 2) AS x
  ) AS w 
  ON w.position=p.id
GROUP BY p.id, p.position

Идея состоит в том, чтобы заменить статус 4 в подвыборке на 3 или 2 в зависимости от того, будем ли мы в настоящее время использовать position или position2 как объединенный position. Внешний выбор продолжает использовать ту же логику, что и раньше.

0 голосов
/ 24 сентября 2011

, поскольку ваши данные не нормализованы (то есть: два столбца, каждый из которых представляет позицию в одной строке), я сначала сделал бы UNION рабочих, а затем применил ваш внешний счет / группу с помощью ... чего-то вродеКаждая часть внутреннего запроса предварительно агрегирует и учитывает только те записи, которые соответствуют статусу 2 или 3 и имеют позицию.Так что, если у вас большой стол, это будет более заметно по производительности.Затем этот результат суммируется на внешнем уровне для всех возможных позиций, используя COALESCE () для предотвращения значений NULL в вашем выходном результате.

SELECT 
      p.id,
      p.position, 
      coalesce( SUM(w.Booked), 0 )  AS booked,
      coalesce( SUM(w.Placed), 0 )  AS placed
   FROM  
      tbl_positions AS p 
         LEFT JOIN 
            ( select w1.Position as PositionID,
                     sum( if( w1.status = 2, 1, 0 )) as Booked,
                     sum( if( w1.status = 3, 1, 0 )) as Placed
                 from 
                     tbl_workers w1
                 where
                         w1.status in ( 2, 3 )
                     and w1.Position > 0
                 group by 
                     PositionID
              union all
              select w2.Position2 as PositionID,
                     sum( if( w2.status = 2, 1, 0 )) as Booked,
                     sum( if( w2.status = 3, 1, 0 )) as Placed
                 from
                     tbl_workers w2
                 where
                         w2.status in ( 2, 3 )
                     and w2.Position2 > 0
                 group by 
                     PositionID ) as w
        on p.id = w.positionID
   group by
       p.id,
       p.position
0 голосов
/ 24 сентября 2011

не совсем уверен, что вы подразумеваете под "оценивать оба поля" - но вот пример того, как суммировать оба:

SELECT
P.ID,
P.POSITION,
((SELECT SUM (CASE W.STATUS WHEN 2 THEN 1 ELSE 0 END) FROM TBL_WORKERS W WHERE W.POSITION = P.ID) + (SELECT SUM (CASE W.STATUS WHEN 2 THEN 1 ELSE 0 END) FROM TBL_WORKERS W WHERE W.POSITION2 = P.ID)) AS BOOKED,
((SELECT SUM (CASE W.STATUS WHEN 3 THEN 1 ELSE 0 END) FROM TBL_WORKERS W WHERE W.POSITION = P.ID) + (SELECT SUM (CASE W.STATUS WHEN 3 THEN 1 ELSE 0 END) FROM TBL_WORKERS W WHERE W.POSITION2 = P.ID)) AS PLACED
FROM TBL_POSITIONS P
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...