2014-03-07 39 views
2

我有一個包含表的數據庫:申請人(或工作候選人),應用程序(候選人申請某個工作),測試,selected_test(任何應用程序都有一組定義的測試)和test_result。如何重構(縮短)此查詢

當我需要出示哪些申請人得分什麼結果的任何應用程序和測試我會用這個查詢:

SELECT applicant.first_name, applicant.last_name, application.job, test.name, test_result.score 
FROM applicant 
INNER JOIN application ON application.applicant_id=applicant.id 
INNER JOIN selected_test ON application.id=selected_test.application_id 
INNER JOIN test ON selected_test.test_id=test.id 
INNER JOIN test_result ON selected_test.test_id=test_result.test_id AND applicant.id=test_result.applicant_id 

我需要做到的是通過一定的測試類型(test.name)以及分揀什麼test.score

這就是我的意思是:

SELECT a.first_name, a.last_name, app.job, iq.score AS iqScore, math.score AS mathScore, personality.score AS personalityScore, logic.score AS logicScore 
FROM applicant a 
INNER JOIN application app ON a.id=app.applicant_id 
LEFT JOIN 

(SELECT app.id AS appId, tr.score 
FROM applicant a 
    INNER JOIN application app ON app.applicant_id=a.id 
    INNER JOIN selected_test st ON app.id=st.application_id 
    INNER JOIN test t ON st.test_id=t.id AND t.name='iq' 
    INNER JOIN test_result tr ON st.test_id=tr.test_id AND a.id=tr.applicant_id) AS iq ON app.id=iq.appId 

LEFT JOIN 
(SELECT app.id AS appId, tr.score 
FROM applicant a 
    INNER JOIN application app ON app.applicant_id=a.id 
    INNER JOIN selected_test st ON app.id=st.application_id 
    INNER JOIN test t ON st.test_id=t.id AND t.name='math' 
    INNER JOIN test_result tr ON st.test_id=tr.test_id AND a.id=tr.applicant_id) AS math ON app.id=math.appId 

LEFT JOIN 
(SELECT app.id AS appId, tr.score 
FROM applicant a 
    INNER JOIN application app ON app.applicant_id=a.id 
    INNER JOIN selected_test st ON app.id=st.application_id 
    INNER JOIN test t ON st.test_id=t.id AND t.name='personality' 
    INNER JOIN test_result tr ON st.test_id=tr.test_id AND a.id=tr.applicant_id) AS personality ON app.id=personality.appId 

LEFT JOIN 
(SELECT app.id AS appId, tr.score 
FROM applicant a 
    INNER JOIN application app ON app.applicant_id=a.id 
    INNER JOIN selected_test st ON app.id=st.application_id 
    INNER JOIN test t ON st.test_id=t.id AND t.name='logic' 
    INNER JOIN test_result tr ON st.test_id=tr.test_id AND a.id=tr.applicant_id) AS logic ON app.id=logic.appId 

ORDER BY mathScore DESC, iqScore DESC, logicScore DESC 

查詢返回一組應用程序,顯示申請人的數據,作業,考試名稱和分數。例如,如果我想要具有較高「數學」分數的候選應用程序,然後是「IQ」中的最高分數,然後是「邏輯」中的最高分數,則'ORDER BY'子句看起來像上面那樣。 該查詢工作正確,但問題是,在實際情況下,它處理大型數據集,我需要一種方法來縮短/重構此查詢。

示例數據庫它的工作原理上是在這裏:

CREATE TABLE IF NOT EXISTS `applicant` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`first_name` varchar(255) NOT NULL, 
`last_name` varchar(255) NOT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=8 ; 

-- 
-- Dumping data for table `applicant` 
-- 

INSERT INTO `applicant` (`id`, `first_name`, `last_name`) VALUES 
(2, 'Jack', 'Redburn'), 
(4, 'Barry', 'Leon'), 
(6, 'Elisabeth', 'Logan'), 
(7, 'Jane', 'Doe'); 

-- -------------------------------------------------------- 

-- 
-- Table structure for table `application` 
-- 

CREATE TABLE IF NOT EXISTS `application` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`applicant_id` int(11) NOT NULL, 
`job` varchar(255) NOT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ; 

-- 
-- Dumping data for table `application` 
-- 

INSERT INTO `application` (`id`, `applicant_id`, `job`) VALUES 
(2, 2, 'Salesman'), 
(4, 4, 'Policeman'), 
(6, 6, 'Journalist'), 
(8, 6, 'Hostess'), 
(9, 7, 'Journalist'); 

-- -------------------------------------------------------- 

-- 
-- Table structure for table `selected_test` 
-- 

CREATE TABLE IF NOT EXISTS `selected_test` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`application_id` int(11) NOT NULL, 
`test_id` int(11) NOT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=24 ; 

-- 
-- Dumping data for table `selected_test` 
-- 

INSERT INTO `selected_test` (`id`, `application_id`, `test_id`) VALUES 
(1, 1, 1), 
(2, 1, 2), 
(3, 1, 3), 
(5, 2, 1), 
(6, 2, 2), 
(7, 2, 3), 
(8, 2, 4), 
(9, 3, 4), 
(10, 3, 2), 
(11, 4, 1), 
(12, 4, 2), 
(13, 4, 3), 
(14, 4, 4), 
(15, 5, 2), 
(16, 5, 3), 
(17, 6, 1), 
(18, 6, 4), 
(19, 7, 3), 
(20, 7, 2), 
(21, 7, 1), 
(22, 8, 2), 
(23, 8, 3); 

-- -------------------------------------------------------- 

-- 
-- Table structure for table `test` 
-- 

CREATE TABLE IF NOT EXISTS `test` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`name` varchar(255) NOT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ; 

-- 
-- Dumping data for table `test` 
-- 

INSERT INTO `test` (`id`, `name`) VALUES 
(1, 'math'), 
(2, 'logic'), 
(3, 'iq'), 
(4, 'personality'); 

-- -------------------------------------------------------- 

-- 
-- Table structure for table `test_result` 
-- 

CREATE TABLE IF NOT EXISTS `test_result` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`applicant_id` int(11) NOT NULL, 
`test_id` int(11) NOT NULL, 
`score` int(11) NOT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=24 ; 

-- 
-- Dumping data for table `test_result` 
-- 

INSERT INTO `test_result` (`id`, `applicant_id`, `test_id`, `score`) VALUES 
(2, 2, 1, 6), 
(3, 4, 1, 7), 
(6, 6, 1, 3), 
(7, 7, 1, 8), 
(9, 2, 2, 15), 
(11, 4, 2, 12), 
(13, 6, 2, 11), 
(14, 7, 2, 9), 
(15, 7, 3, 105), 
(16, 6, 3, 112), 
(18, 4, 3, 108), 
(20, 2, 3, 117), 
(22, 4, 4, 70); 

這裏是什麼結果如下: 第一個查詢只顯示你的數據是如何相關:

First query is just to show you how data is related

的大查詢,水平顯示得分數據,因此可以按測試名稱和得分排序:

The large query, shows data horizontally so it is possible to sort by test name and score

+0

如果您顯示2個查詢的結果會有所幫助,但我認爲您想要查看的是對數據進行透視 –

+0

我剛剛爲這兩個查詢添加了結果圖像。 –

回答

1

告誡我不知道MySQL的

谷歌搜索MySQL的支點給出了這樣的結果http://en.wikibooks.org/wiki/MySQL/Pivot_table

因此,如果我們申請使用test.id作爲種子數(這是考試相同的邏輯在谷歌搜索的例子中)我們得到這個:

SQLFIDDLE

select first_name, last_name, job, 
    sum(score*(1-abs(sign(testid-1)))) as math, 
    sum(score*(1-abs(sign(testid-2)))) as logic, 
    sum(score*(1-abs(sign(testid-3)))) as iq, 
    sum(score*(1-abs(sign(testid-4)))) as personality 
from 
(
    SELECT applicant.first_name, applicant.last_name, application.job, test.name, test_result.score, test.id as testid 
    FROM applicant 
    INNER JOIN application ON application.applicant_id=applicant.id 
    INNER JOIN selected_test ON application.id=selected_test.application_id 
    INNER JOIN test ON selected_test.test_id=test.id 
    INNER JOIN test_result ON selected_test.test_id=test_result.test_id AND applicant.id=test_result.applicant_id 
) t 
group by first_name, last_name, job 

現在您已經有了簡短的查詢功能,可以根據需要應用排序 - 您可以使用case聲明order by根據需要動態更改順序...

+0

好吧,只有45分鐘讓我得到它; - D工作正常。非常感謝 –

+0

@DjuroMandinic大聲笑它從我發佈這個問題的角度花了我12分鐘發佈那個答案(工作小提琴) - 我不這樣做mysql(僅ms/tsql):D - 這是一個有趣的舊世界 –

-1

我注意到你只定義了主鍵。當您爲其他字段編制索引時,您應該看到顯着的性能提升。索引至少如下:application.applicant_id,selected_test.application_id,selected_test.test_id,test_result.applicant_id,test_result.test_id,test_result.score。

您可能會感到驚訝,這會加快您的速度。事實上,mysql告訴我們這是提高性能的最佳方式:https://dev.mysql.com/doc/refman/5.5/en/optimization-indexes.html

+0

毫無疑問,索引會提高性能。然而,查詢恕我直言,主要問題是,它包括重複大塊的文本,只有測試名稱不同。必須有更好的方式來做到這一點,但我錯過了它。 –