2010-09-18 31 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