正确完成使用group by连接4个表

时间:2013-04-04 11:42:42

标签: php mysql join

我是使用高级SQL查询的新手,我正在努力解决一个问题。

我在php中创建了预订系统,它使用了4个表:

     
  • site_days
  •  
  • site_timeslots
  •  
  • site_bookings
  •  
  • site_teams
     
  • 每个site_team都与site_booking相关
  •  
  • 每个site_booking都与site_timeslot
  • 相关  
  • 每个site_timeslot与site_days
  • 相关

可以有更多与一个site_day相关的site_timeslots 可以有更多与一个site_timeslot相关的site_bookings 可以有更多与一个site_bookings相关的site_teams

您可以使用此sql创建测试表:

-- Adminer 3.6.3 MySQL dump

SET NAMES utf8;
SET foreign_key_checks = 0;
SET time_zone = 'SYSTEM';
SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO';

DROP TABLE IF EXISTS `site_bookings`;
CREATE TABLE `site_bookings` (
  `id` int(11) NOT NULL auto_increment,
  `timeslot_id` int(11) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

INSERT INTO `site_bookings` (`id`, `timeslot_id`) VALUES
(1, 6443);

DROP TABLE IF EXISTS `site_days`;
CREATE TABLE `site_days` (
  `id` int(11) NOT NULL auto_increment,
  `date` date NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=93 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

INSERT INTO `site_days` (`id`, `date`) VALUES
(85,    '2013-04-01'),
(92,    '2013-04-02');

DROP TABLE IF EXISTS `site_teams`;
CREATE TABLE `site_teams` (
  `id` int(11) NOT NULL auto_increment,
  `booking_id` int(11) NOT NULL,
  `name` varchar(100) collate utf8_bin NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

INSERT INTO `site_teams` (`id`, `booking_id`, `name`) VALUES
(1, 1,  'Avengers'),
(2, 1,  'Big Five');

DROP TABLE IF EXISTS `site_timeslots`;
CREATE TABLE `site_timeslots` (
  `id` int(11) NOT NULL auto_increment,
  `day_id` int(11) NOT NULL,
  `date` date NOT NULL,
  `starts` time NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7152 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

INSERT INTO `site_timeslots` (`id`, `day_id`, `date`, `starts`) VALUES
(6443,  85, '2013-04-01',   '08:00:00'),
(6444,  85, '2013-04-01',   '08:10:00'),
(7098,  92, '2013-04-02',   '08:00:00'),
(7099,  92, '2013-04-02',   '08:10:00');

因此,我希望获得表site_timeslots的所有时间段,只需要一些额外的信息: - 对于每个site_timeslot我想知道所有相关预订中的site_teams总数到该时间段(例如,如果该site_timeslot有2个site_bookings,每个有site_teams,那么总计数应为4)以及相关预订的数量

我试过这个sql:

SELECT `site_teams`.`id` AS site_teams_id, `site_teams`.`name` AS site_teams_name, `site_teams`.`booking_id` AS site_teams_booking_id, `site_days`.`id` AS site_days_id, `site_days`.`date` AS site_days_date, `site_timeslots`.`id` AS site_timeslots_id, `site_timeslots`.`starts` AS site_timeslots_starts, `site_bookings`.`id` AS site_bookings_id, `site_bookings`.`timeslot_id` AS site_bookings_timeslot_id
FROM (`site_days`)
LEFT JOIN `site_timeslots` ON `site_timeslots`.`day_id` = `site_days`.`id`
LEFT JOIN `site_bookings` ON `site_bookings`.`timeslot_id` = `site_timeslots`.`id`
LEFT JOIN `site_teams` ON `site_teams`.`booking_id` = `site_bookings`.`id`
GROUP BY `site_teams`.`booking_id`

- >但我不会得到没有任何site_bookings的时间段,请我如何改变这个SQL查询以获得结果:

      
  1. 每行site_timeslot
  2.   
  3. 新列'count_of_site_bookings'中与该site_timeslot相关的site_bookings计数
  4.   
  5. 与新列'count_of_site_teams'中与该site_timeslot相关的所有site_bookings相关的site_teams计数

1 个答案:

答案 0 :(得分:1)

您可以通过LEFT JOINING从site_timeslots开始,然后在2个相关字段上使用COUNT来获取您之后的总数

SELECT

  sti.*,
  COUNT(DISTINCT sb.id) AS count_of_site_bookings,
  COUNT(DISTINCT ste.id) AS count_of_site_teams

FROM site_timeslots sti

INNER JOIN site_days sd
  ON sd.id = sti.day_id


LEFT JOIN site_bookings sb
ON sb.timeslot_id = sti.id

LEFT JOIN site_teams ste
ON ste.booking_id = sb.id

GROUP BY sti.id

您可以在SQL Fiddle http://sqlfiddle.com/#!2/1a253/2

上找到此信息

由于我的假设不正确,我还做了一个先前的版本使用子查询,如果您想查看它以供参考,它也可以在http://sqlfiddle.com/#!2/9ccf2/10

获得