2015-11-10 12 views
7

会社やその詳細、取引が存在しない場合でも参加しようとしています。別のテーブルからカウントを選択しているときに左結合が機能していない

私はコースに行くユーザーの数を計上するためにトランザクションをカウントしています。トランザクションがない場合、会社と詳細に参加したいが、カウントは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), 

だから私は得ることができますどのように私の瞬間に、それが参加されていないため、すべてが

+14

'left join'はうまく動作します。条件を 'where'節から' on'節に移す必要があります。率直に言えば、「左結合」と「右結合」を混在させたクエリに従うのは本当に難しいですが、どの条件がどこに行くのかを把握できるようにクエリを理解する必要があります。 –

+0

あなたの散文は、残されたものではなく、会社への正しい参加を望むことを示唆しています。 –

+0

は、私は上の無い表情で、右の参加に追加しようとしました:( –

答えて

5

Gordon Linoffが最初のコメントで提案したように、の条件をWHERE句からLEFT JOINに移動します。もちろん

、あなたはまた、列明示的に代わりの*を一覧表示し、作業にCOUNTに対応するGROUP BYを追加する必要があります。

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' 

(誰もがこの質問とあなたが2年後に可能性があなたのコードを維持するだろう次の人を、読みとして)それは、これらのフィールドが属しているテーブルのクエリを読んで新しい人には明確ではありません。

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

は、私は完全に別のルートを行くことをお勧めマッチしていても、細部に仕事に参加し、左の結合を使用しないでください。トレーニングテーブルのすべてのデータが必要なので、別のテーブルから集計(あなたの場合はカウント)したいので、集計を別のサブクエリに分割することをお勧めします。ここでは(私も物事を単純化するために、あなたのテーブルにエイリアスを追加注意してください)私の意味は次のとおりです。

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が返されます。

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 

0

問題が複数行のクエリでしょう決して結果である:

これはあなたにこのような何かを与えるだろう。

使用GROUPBYとして、またはネストされたクエリは、他の回答で述べています。

関連する問題