当我从另一个表中选择计数时,左连接不起作用

时间:2015-11-10 15:31:55

标签: mysql sql

我正在尝试加入公司及其详细信息,以及交易,即使它们不存在。

我正在计算交易数量,以确定有多少用户参加课程,如果没有交易,我仍然想加入公司和详细信息,但计数将为0,在我的查询中,正在选择training_company表,但是由于某种原因没有选择training_details:

SELECT training.*, count(distinct training_transactions.training_transaction_course) as completed_training_payments 
 FROM training
LEFT JOIN training_company
    ON training.course_main = training_company_id
LEFT JOIN training_details
    ON training.course_main = training_details_company
LEFT JOIN training_transactions
    ON training.course_user = training_transactions.training_transaction_user
WHERE course_id = ?
        AND       training_transactions.training_transaction_status = 'complete'
        AND       training_transactions.training_transaction_payment_status = 'complete'
        AND course_enabled = 'enabled'

training_company:

CREATE TABLE IF NOT EXISTS `training_company` (
  `training_company_id` int(11) NOT NULL,
  `training_company_name` varchar(100) NOT NULL,
  `training_company_user` int(11) NOT NULL,
  `training_company_enabled` varchar(50) NOT NULL DEFAULT 'enabled',
  `training_company_has_avatar` int(5) NOT NULL DEFAULT '0',
  `training_company_has_banner` int(5) NOT NULL DEFAULT '0'
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1;

--
-- Dumping data for table `training_company`
--

INSERT INTO `training_company` (`training_company_id`, `training_company_name`, `training_company_user`, `training_company_enabled`, `training_company_has_avatar`, `training_company_has_banner`) VALUES
(1, '123', 1, 'enabled', 0, 0),

training_details:

CREATE TABLE IF NOT EXISTS `training_details` (
  `training_details_id` int(11) NOT NULL,
  `training_details_user` int(11) NOT NULL,
  `training_details_company` int(11) NOT NULL,
  `training_details_registration_number` varchar(10) NOT NULL,
  `training_details_type` varchar(100) NOT NULL,
  `training_details_name` varchar(100) NOT NULL,
  `training_details_street` varchar(100) NOT NULL,
  `training_details_town` varchar(100) NOT NULL,
  `training_details_county` varchar(100) NOT NULL,
  `training_details_postcode` varchar(100) NOT NULL,
  `training_details_country` varchar(100) NOT NULL,
  `training_details_company_name` varchar(100) NOT NULL,
  `training_details_company_street` varchar(100) NOT NULL,
  `training_details_company_town` varchar(100) NOT NULL,
  `training_details_company_county` varchar(100) NOT NULL,
  `training_details_company_postcode` varchar(100) NOT NULL,
  `training_details_company_country` varchar(100) NOT NULL,
  `training_details_total_employees` varchar(100) NOT NULL,
  `training_details_fax` varchar(100) NOT NULL,
  `training_details_landline` varchar(100) NOT NULL,
  `training_details_mobile` varchar(50) NOT NULL,
  `training_details_email` varchar(50) NOT NULL,
  `training_details_website` varchar(250) NOT NULL,
  `company_differs_address` int(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1;

--
-- Dumping data for table `training_details`
--

INSERT INTO `training_details` (`training_details_id`, `training_details_user`, `training_details_company`, `training_details_registration_number`, `training_details_type`, `training_details_name`, `training_details_street`, `training_details_town`, `training_details_county`, `training_details_postcode`, `training_details_country`, `training_details_company_name`, `training_details_company_street`, `training_details_company_town`, `training_details_company_county`, `training_details_company_postcode`, `training_details_company_country`, `training_details_total_employees`, `training_details_fax`, `training_details_landline`, `training_details_mobile`, `training_details_email`, `training_details_website`, `company_differs_address`) VALUES
(1, 0, 1, '0', '', '123', '123', '123', '123456', 'WN8', 'Australia', '123', '123', '123', '', 'WN8', 'Australia', '', '', '', '', '', '', 4),

训练:

CREATE TABLE IF NOT EXISTS `training` (
  `course_id` int(11) NOT NULL,
  `course_user` int(11) NOT NULL,
  `course_main` int(11) NOT NULL,
  `course_type` varchar(255) NOT NULL,
  `course_name` varchar(255) NOT NULL,
  `course_description` text NOT NULL,
  `course_location` varchar(255) NOT NULL,
  `course_duration` varchar(255) NOT NULL,
  `course_fitness_type` varchar(255) NOT NULL,
  `course_instructor_name` varchar(255) NOT NULL,
  `course_price` int(15) NOT NULL,
  `course_start_date` date NOT NULL,
  `course_max_attendees` int(8) NOT NULL,
  `course_accommodation` varchar(255) NOT NULL,
  `course_accommodation_price` varchar(255) NOT NULL,
  `course_status` varchar(50) NOT NULL,
  `course_enabled` varchar(10) NOT NULL DEFAULT 'enabled',
  `course_location_name` varchar(255) NOT NULL,
  `course_location_street` varchar(255) NOT NULL,
  `course_location_town` varchar(255) NOT NULL,
  `course_location_county` varchar(255) NOT NULL,
  `course_location_postcode` varchar(255) NOT NULL,
  `course_location_country` varchar(255) NOT NULL,
  `course_certificate` varchar(250) NOT NULL,
  `course_certificate_valid` int(30) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;

--
-- Dumping data for table `training`
--

INSERT INTO `training` (`course_id`, `course_user`, `course_main`, `course_type`, `course_name`, `course_description`, `course_location`, `course_duration`, `course_fitness_type`, `course_instructor_name`, `course_price`, `course_start_date`, `course_max_attendees`, `course_accommodation`, `course_accommodation_price`, `course_status`, `course_enabled`, `course_location_name`, `course_location_street`, `course_location_town`, `course_location_county`, `course_location_postcode`, `course_location_country`, `course_certificate`, `course_certificate_valid`) VALUES
(1, 3, 1, 'Hazardous', '123', 'dddddddddddddd', 'other', '14', 'lol', 'lol', 123, '2015-11-09', 4, '0', '', 'pending', 'enabled', '123', '123', '123', '123456', '123', 'Australia', '123', 2),

那么我怎样才能让我的联盟处理细节问题,因为即使所有内容都匹配,目前它还没有加入

4 个答案:

答案 0 :(得分:5)

正如Gordon Linoff在第一条评论中所建议的那样,将training_transactions条款中涉及WHERE的条件移至LEFT JOIN

当然,您还应该明确列出列而不是*,并为GROUP BY添加相应的COUNT

SELECT 
    training.course_id
    ,training.course_user
    ...
    ,count(distinct training_transactions.training_transaction_course) as completed_training_payments 
FROM
    training
    LEFT JOIN training_company ON training.course_main = training_company_id
    LEFT JOIN training_details ON training.course_main = training_details_company
    LEFT JOIN training_transactions
        ON  training_transactions.training_transaction_user = training.course_user
        AND training_transactions.training_transaction_status = 'complete'
        AND training_transactions.training_transaction_payment_status = 'complete'
WHERE
    training.course_id = ?
    AND training.course_enabled = 'enabled'
GROUP BY
    training.course_id
    ,training.course_user
    ...

在此查询中,您还应该注意一些事项。

WHERE
    course_id = ?
    AND course_enabled = 'enabled'

对于阅读该问题的新人(因为每个人都在阅读这个问题以及将要维护您的代码的下一个人,这可能是您在两年时间内)这些字段属于哪个表格,目前尚不清楚。始终尝试明确指出表格,如下所示:

WHERE
    training.course_id = ?
    AND training.course_enabled = 'enabled'

使用别名也很有帮助。

以类似的方式,不清楚JOIN

中发生了什么
    LEFT JOIN training_company ON training.course_main = training_company_id
    LEFT JOIN training_details ON training.course_main = training_details_company

在简化此问题的查询时,这只是一个疏忽,或者这是您真正的代码吗?无论如何,请包括表名(或别名)。

LEFT JOIN training_company ON training.course_main = training_company.training_company_id
LEFT JOIN training_details ON training.course_main = training_details.training_details_company

答案 1 :(得分:1)

我建议完全不同的路线,不要使用左连接。由于您需要来自训练表的所有数据,并且您希望从不同的表中聚合(在您的情况下计数),我建议将聚合分解为单独的子查询。这就是我的意思(注意我在表格中添加了别名以简化操作):

SELECT t.*,
       (SELECT count(distinct tt.training_transaction_course)
          FROM training_company tc        
          JOIN training_details td ON td.course_main = tc.training_details_company
          JOIN training_transactions tt ON t.course_user = tt.training_transaction_user
         WHERE t.course_main = tc.training_company_id
           AND tt.training_transaction_status = 'complete'
           AND tt.training_transaction_payment_status = 'complete')
        as completed_training_payments 
 FROM training t
WHERE t.course_id = ?
  AND t.course_enabled = 'enabled'

这将保证训练表中与输入的course_id匹配的每一行返回一行。此外,如果子查询没有返回任何行,则它将返回0.

答案 2 :(得分:0)

这有一些问题。首先,如果没有training_transactions的模式,很难重现。

此外,从您的描述和架构中可以看出,您希望在第一个表上进行内部联接。如果我读得对,training总会有一家公司。 training_details似乎与查询无关,如果它们不是,则会提供交叉产品,因此完全不考虑。

我假设用户加入交易是错误的,因为你有一个training_transaction_course我认为是正确的外键。

计数是错误的 - 它不是如何工作的,如果你想要计数,你需要一个GROUP BY子句。

WHERE子句对我来说是正确的,因为元素没有在任何连接中使用。

这会给你这样的东西:

SELECT training.course_id, -- everything you put here needs to go in the group by clause
    count(training_transactions.training_transaction_course) as completed_training_payments
   FROM training
   JOIN training_company
       ON training.course_main = training_company_id
   LEFT JOIN training_transactions
       ON training.course_id = training_transactions.training_transaction_course
   WHERE course_id = ?
       AND training_transactions.training_transaction_status = 'complete'
       AND training_transactions.training_transaction_payment_status = 'complete'
       AND course_enabled = 'enabled'
   GROUP BY training.course_id, training_transactions.training_transaction_course

答案 3 :(得分:0)

问题是您的查询从不会产生多行。

使用Groupby或嵌套查询,如其他答案中所述。