2010-09-18 38 views
4

我有一個數據庫,我存儲的關鍵字分組到項目和數據相關的每個關鍵字,然後我顯示datagrids foreach項目與每個關鍵字和所有檢索從同一個表「數據」的幾個列。我有4個表格,關鍵字,項目,group_keywords和數據。 「關鍵字」僅存儲關鍵字,「投影」項目名稱,「group_keywords」分配給該項目的關鍵字的關鍵字id,而「data」是關鍵字的所有數據所關聯的所有數據, .id和一個名稱列來標識數據名稱。如何將行變成列?

我們檢索關鍵字+的所有數據進行一個項目,我使用此查詢:

SELECT * FROM `group_keywords` 
INNER JOIN keywords on keywords.id = keyword_id 
INNER JOIN data ON data.id = keywords.id 
WHERE `group_id` = (SELECT `id` FROM `projects` WHERE `name` = 'ProjectName' 

這讓我有點像

id group_id keyword_id id keyword  id name value 
    12 5 52 52 absorption food  52 data_name_x1 6 
    12 5 52 52 absorption food  52 data_name_x2 8 
    12 5 52 52 absorption food  52 data_name_x3 26 
    12 5 52 52 absorption food  52 data_name_x4 2 
... 

但我要的是得到:

id group_id keyword_id id keyword id data_name_x1 data_name_x2 data_name_x3 data_name_x4 
12 5 52 52 absorption food  52  6    8    26    2 
... 

這樣我就可以進行排序,並使用分頁爲伊斯利的數據網格,否則我不知道該怎麼做,是當使用大數據集時,我不能將所有內容都轉儲到數組中,數據太多。

這是架構:

-- -------------------------------------------------------- 
-- Table structure for table `keywords` 

CREATE TABLE IF NOT EXISTS `keywords` (
    `id` int(10) unsigned NOT NULL auto_increment, 
    `keyword` varchar(255) NOT NULL, 
    UNIQUE KEY `id` (`id`), 
    UNIQUE KEY `keyword` (`keyword`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=115386 ; 


-- -------------------------------------------------------- 
-- Table structure for table `data` 

CREATE TABLE IF NOT EXISTS `data` (
    `id` int(10) unsigned NOT NULL, 
    `name` varchar(100) NOT NULL, 
    `value` varchar(15) NOT NULL, 
    UNIQUE KEY `id` (`id`,`name`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 


-- -------------------------------------------------------- 
-- Table structure for table `projects` 
-- 

CREATE TABLE IF NOT EXISTS `projects` (
    `id` int(10) NOT NULL auto_increment, 
    `name` varchar(100) NOT NULL, 
    `parent` varchar(100) default NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=21 ; 


-- -------------------------------------------------------- 
-- Table structure for table `group_keywords` 

CREATE TABLE IF NOT EXISTS `group_keywords` (
    `id` int(10) NOT NULL auto_increment, 
    `group_id` int(10) NOT NULL, 
    `keyword_id` int(10) unsigned NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `group_id` (`group_id`,`keyword_id`), 
    KEY `keyword_id` (`keyword_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=119503 ; 


-- -------------------------------------------------------- 
-- Constraints for table `data` 
-- 
ALTER TABLE `data` 
    ADD CONSTRAINT `data_ibfk_1` FOREIGN KEY (`id`) REFERENCES `keywords` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; 

-- -------------------------------------------------------- 
-- Constraints for table `group_keywords` 
-- 
ALTER TABLE `group_keywords` 
    ADD CONSTRAINT `group_keywords_ibfk_1` FOREIGN KEY (`keyword_id`) REFERENCES `keywords` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; 

回答

3

該操作傳統上被稱爲「逆透視」和幾個RDBMS的支持,但MySQL不似乎是其中之一。你有兩個選擇,在SQL中執行或在PHP中執行。在MySQL中,它看起來像這樣具有自連接(我不知道哪個字段有資格作爲您的ID字段,所以請原諒我創建自己的示例)。從性能的角度來看,確保您索引ID和列名稱,否則這些連接將抓取。

shapes 
ID Name Value 
1 Color Red 
1 Shape Circle 
... for more "columns" 
2 Color Green 
2 Shape Square 
... for more "columns" 

SELECT 
    A.ID, 
    B.Value as Color, 
    C.Value as Shape 
    ... for more "columns" 
FROM shapes A 
LEFT JOIN shapes B ON B.ID = A.ID AND B.Name = 'Color' 
LEFT JOIN shapes C ON C.ID = A.ID AND C.Name = 'Shape' 
... for more "columns" 

這應該淨美(除非我的頭-SQL解析器misrunning今晚):

ID Color Shape 
1 Red  Circle 
2 Green Square 

對於PHP版本,你不一定要加載一個數組,你可以流它。按PK排序並沿着它設置屬性。在僞代碼:

Set X to undefined 
Get a Record 
    Check the ID property, if it's different than X, create a new object, set X to the new ID, and yield the previous object 
    Set the property of the object based on the "Name" column of our result 

希望這有助於!

+0

幫助了很多,我只需做一個小改動,使用LEFT JOIN而不是INNER,或者如果其中一個「列」不存在,它將返回0行。但我現在有一個工作查詢,只需稍微優化即可。非常感謝。 – jarkam 2010-09-18 15:57:43

+0

好點,左連接可能會更有意義。我已經改變了後代的答案,很高興幫助! – 2010-09-18 23:29:21