2010-04-10 51 views
0

希望這比我想象的要複雜。MySQL大師:如何用一個查詢從MySQL數據庫中提取複雜的數據網格?

我有一張公司名單和另一張工作表,第三張表中包含每個公司每項工作中每位員工的單個條目。 注意:有些公司在某些工作中不會有員工,有些公司在一些工作中會有不止一個員工。

公司表有companyidcompanyname領域,工作表中有一個jobidjobtitle場,僱員表有employeeidcompanyidjobidemployeename領域。

我想建立這樣一個表:

 
     +-----------+-----------+-----------+ 
     | Company A | Company B | Company C | 
------+-----------+-----------+-----------+ 
Job A | Emp 1  | Emp 2  |   | 
------+-----------+-----------+-----------+ 
Job B | Emp 3  |   | Emp 4  | 
     |   |   | Emp 5  | 
------+-----------+-----------+-----------+ 
Job C |   | Emp 6  |   | 
     |   | Emp 7  |   | 
     |   | Emp 8  |   | 
------+-----------+-----------+-----------+ 

我以前一直在結果集中的工作循環,併爲每個作業,在結果集中各公司的循環,併爲每個公司,循環遍歷每個員工並將其打印在一張表格中(總體而言,表現不應被視爲考慮因素)。該應用程序越來越受歡迎,現在我們有100家公司和數百個工作,並且服務器正在退出(所有ID字段都被編入索引)。

有關如何編寫單個查詢以獲取此數據的任何建議?我不需要公司名稱或職位(顯然),但我確實需要一些方法來確定結果中的每行應該打印的位置。我想象的結果集只包含一長串加入的員工,我可以編寫一個循環以使用companyidemployeeid值告訴我何時創建新的單元格或表格行。只要沒有ZERO員工,這種方法就行得通;我想爲此需要一個NULL員工姓名?我完全在錯誤的軌道上?

在此先感謝您的任何想法!

+0

我認爲你可能會發現查詢這樣做會非常緩慢...... – SeanJA 2010-04-10 21:11:29

回答

2

訣竅是不是在查詢了這麼多(像

SELECT jobtitle, companyname, employeename 
    FROM employee AS e 
    RIGHT JOIN company AS c ON e.companyid = c.companyid 
    RIGHT JOIN job AS j ON e.jobid = j.jobid 
    WHERE ... 
    ORDER BY j.jobtitle, c.companyname 

),你如何處理的結果。對於每個結果行,當公司更改時啓動新的表格單元格,並在作業標題更改時啓動新的表格行。最棘手的部分是確定何時需要輸出一個關閉標記。

+0

感謝您的支持 - 我已經有了這個工作,並且在我的開發服務器上看起來不錯,但是一旦我放入我的共享主機服務器(16M內存,執行30秒),就會耗盡內存。我要檢查我的PHP是否有泄漏。 – iopener 2010-04-10 22:36:53

+0

@iopener:如果可能,請嘗試使用無緩衝的查詢(http://stackoverflow.com/questions/131139/streaming-large-result-sets-with-mysql-4-1-x-connector-j; http:// stackoverflow.com/questions/1448661/django-unbuffered-mysql-query;如果使用PHP,默認情況下PDO是無緩衝的),這樣腳本就不必保存整個結果集(儘管你無法獲得直到ent的結果行數)。也請嘗試SeanJA的建議來限制/分頁結果。查看查詢的執行情況,無論是在腳本中還是在其自身(http://dev.mysql.com/doc/refman/5.1/en/explain.html)。 – outis 2010-04-10 23:36:54

+0

最後,我將這些表內聯在一起,並允許跳過NULL匹配。在我的PHP中,我循環遍歷了每個companyid和jobid的組合,並檢查它是否與當前結果記錄匹配。如果是這樣,我打印它;如果沒有,我關閉單元格並移動到companyid和jobid的下一個組合。由於數據按照與單元打印相同的順序進行排序,因此效果很好:在32MB內存的情況下,無法在兩分鐘內完成的頁面現在可以在6秒內完成,並且只有16MB。 感謝大家的意見! – iopener 2010-04-11 00:43:01

0

我認爲Joins可能是您正在尋找的答案。

+0

左連接實際上...這可能不存在,可能不存在...結果是一個緩慢的查詢 – SeanJA 2010-04-10 21:14:34

+1

@SeanJA:result如果表格索引正確,則不必太慢。 – outis 2010-04-10 21:17:48

+0

它仍然(通常)比獲取數據並使用代碼將其處理成表格要慢。 – SeanJA 2010-04-10 21:23:12

2

我想你問的,這可能是更接近:

SELECT j.jobtitle, e1.employeeName, e2.employeename, e3.employeename 
FROM jobs AS j 
LEFT OUTER JOIN employee AS e1 ON e1.jobid = j.jobid AND e1.companyid = 1 
LEFT OUTER JOIN employee AS e2 ON e2.jobid = j.jobid AND e2.companyid = 2 
LEFT OUTER JOIN employee AS e3 ON e3.jobid = j.jobid AND e3.companyid = 3 
ORDER BY j.jobtitle 

左外連接會給你NULL在沒有比賽。

您可以看到在添加幾家公司後它會變得如何醜陋。如果你有索引你的ID列,這將不會很慢。不要害怕加入 - 數據庫是爲它而做的!

+0

我得到了這個查詢的要點,這是一個非常聰明的想法。我使用PHP代碼生成SQL,將其打印出來並在phpMyAdmin中運行,並且運行超過15分鐘而未完成。我想知道它是否與數據中有大量的NULL值有關? – iopener 2010-04-11 00:38:29

0

變量替換爲相應的公司標識和提高@@group_concat_max_len如果需要的話:

SELECT 
    jobtitle as '', 
    GROUP_CONCAT(IF([email protected]_id, employeename,NULL) SEPARATOR '\n') as `Company A`, 
    GROUP_CONCAT(IF([email protected]_id, employeename,NULL) SEPARATOR '\n') as `Company B`, 
    GROUP_CONCAT(IF([email protected]_id, employeename,NULL) SEPARATOR '\n') as `Company C` 
FROM employee 
LEFT JOIN company 
    USING (companyid) 
LEFT JOIN job 
    USING (jobid) 
GROUP BY jobid; 

UPD:好像你甚至都不需要一個連接到運營商表,因此它可能會被簡化爲:

SELECT 
    jobtitle as '', 
    GROUP_CONCAT(IF([email protected]_id, employeename,NULL) SEPARATOR '\n') as `Company A`, 
    GROUP_CONCAT(IF([email protected]_id, employeename,NULL) SEPARATOR '\n') as `Company B`, 
    GROUP_CONCAT(IF([email protected]_id, employeename,NULL) SEPARATOR '\n') as `Company C` 
FROM employee 
LEFT JOIN job 
    USING (jobid) 
GROUP BY jobid; 

但是,在這種情況下,您可能需要員工表中的companyid字段索引。