2012-05-21 37 views
2
SELECT u.users_username, u.givenname, u.familyname, u.studentassent, u.parentconsent, u.birthdate, u.gender 
FROM users AS u 
JOIN classes_users as c 
ON c.users_username = u.users_username 
JOIN classes_users as x 
ON c.classes_id = x.classes_id 
WHERE x.users_username = "johnny" AND x.role = "teacher" 

或者這個SELECT應該使用連接還是子查詢?

SELECT u.users_username, u.givenname, u.familyname, u.studentassent, u.parentconsent, u.birthdate, u.gender 
FROM users AS u 
WHERE u.users_username 
IN (
    SELECT c.users_username 
    FROM classes_users as c 
    JOIN classes_users as x 
    ON c.classes_id = x.classes_id 
    WHERE x.users_username = "johnny" AND x.role = "teacher" 
) 

我想第一個是更好,但我仍然在學習如何寫出更好的SQL語句是不是發生了什麼,所有的內部明確,使一個更好的說法比在這種情況下的其他。

如果有更好的寫作方式比我寫的兩種方式,請讓我知道。謝謝。編輯: 有老師和學生。通過查看classes_users表可以找到他們在任何班級中作爲學生或教師的位置。我想要做的是,當給予用戶時,找到他是老師的班級,然後返回這些班級中的所有學生。

這裏是我的DB模式:

-- ----------------------------------------------------- 
-- Table `kcptech`.`users` 
-- ----------------------------------------------------- 
CREATE TABLE IF NOT EXISTS `kcptech`.`users` (
`users_username` VARCHAR(63) NOT NULL , 
`password` VARCHAR(255) NULL DEFAULT NULL , 
`salt` VARCHAR(127) NULL DEFAULT NULL , 
`givenname` VARCHAR(96) NULL DEFAULT NULL , 
`familyname` VARCHAR(128) NULL DEFAULT NULL , 
`privileges` TINYINT NULL DEFAULT NULL , 
`studentassent` TINYINT(1) UNSIGNED NULL DEFAULT NULL , 
`parentconsent` TINYINT(1) UNSIGNED NULL DEFAULT NULL , 
`birthdate` DATE NULL DEFAULT NULL , 
`gender` VARCHAR(1) NULL DEFAULT NULL , 
`registration` TIMESTAMP NULL DEFAULT NULL , 
PRIMARY KEY (`users_username`) , 
UNIQUE INDEX `uname_UNIQUE` (`users_username` ASC)) 
ENGINE = InnoDB; 




-- ----------------------------------------------------- 
-- Table `kcptech`.`classes` 
-- ----------------------------------------------------- 
CREATE TABLE IF NOT EXISTS `kcptech`.`classes` (
`classes_id` INT UNSIGNED NOT NULL AUTO_INCREMENT , 
`course` VARCHAR(127) NULL , 
`period` VARCHAR(31) NULL DEFAULT '' , 
`organization` VARCHAR(127) NULL DEFAULT '' , 
PRIMARY KEY (`classes_id`) , 
UNIQUE INDEX `id_UNIQUE` (`classes_id` ASC)) 
ENGINE = InnoDB; 


-- ----------------------------------------------------- 
-- Table `kcptech`.`classes_users` 
-- ----------------------------------------------------- 
CREATE TABLE IF NOT EXISTS `kcptech`.`classes_users` (
`classes_id` INT UNSIGNED NOT NULL , 
`users_username` VARCHAR(64) NOT NULL , 
`role` VARCHAR(12) NOT NULL , 
PRIMARY KEY (`classes_id`, `users_username`) , 
INDEX `fk_class_users__users_users_username` (`users_username` ASC) , 
INDEX `fk_class_users__class_class_id` (`classes_id` ASC) , 
CONSTRAINT `fk_class_users__users_users_username` 
    FOREIGN KEY (`users_username`) 
    REFERENCES `kcptech`.`users` (`users_username`) 
    ON DELETE NO ACTION 
    ON UPDATE NO ACTION, 
CONSTRAINT `fk_class_users__class_class_id` 
    FOREIGN KEY (`classes_id`) 
    REFERENCES `kcptech`.`classes` (`classes_id`) 
    ON DELETE NO ACTION 
    ON UPDATE NO ACTION) 
ENGINE = InnoDB; 
+0

請發佈您的架構並描述您要實現的目標。如果我理解正確,那麼您試圖爲名爲johnny並且有老師角色的用戶提供信息?我懷疑我們可以提出一些模式改進。此外,JOIN將總是擊敗這樣的情況的子查詢。此外,這篇文章可能更適合codereview.stackexchange.com – Corbin

+0

我已經添加了一個數據庫模式以清晰起見。 – user594044

回答

5

第一個是更好的,假設(classes_id, users_username)是獨一無二的。

MySQL不能進行半連接(IN構造),其內部查詢處於領先地位。因此,IN查詢將始終使用users作爲主表,而對於JOIN查詢,優化程序可以選擇前導表。如果(classes_id, users_username)不是唯一的,則查詢在語義上不等同。您需要將DISTINCT添加到聯接查詢中。

+0

+1對於優秀的解釋! –

+0

爲了清晰起見,我添加了數據庫模式。 – user594044

+0

@ user594044:在'classes_users(users_username,role)'上創建一個複合索引,並使用你的第一個查詢。 – Quassnoi

相關問題