使用键/值对从表中过滤和分组数据

时间:2013-03-24 00:52:36

标签: mysql

我正在努力从数据收集环境的CSV格式数据的“标准化”数据库中提取数据。这将使用PHP / MySQL / JSON完成,目的是绘制数据。我想我有过滤部分,但我需要帮助进行旋转。我们的想法是使用keyNames字段作为数据的过滤器。

以下是查询:

select d.testId,d.rowId,f.keyName,f.keyValue from tests t 
inner join data d on t.testId = d.testId 
inner join data c on t.testId = c.testId and c.rowId = d.rowId 
join data f on f.testId = t.testId and f.rowId = d.rowId 
where (d.keyName = 'voltage' and d.keyValue < 5) and (c.keyName = 'temperature' and c.keyValue = 30) and (t.testType = 'testType1');

结果:

+--------+-------+-------------+----------+
| testId | rowId | keyName     | keyValue |
+--------+-------+-------------+----------+
|      1 |     1 | voltage     |        4 |
|      1 |     1 | temperature |       30 |
|      1 |     1 | velocity    |       20 |
|      1 |     2 | voltage     |        4 |
|      1 |     2 | temperature |       30 |
|      1 |     2 | velocity    |       21 |
|      2 |     1 | voltage     |        4 |
|      2 |     1 | temperature |       30 |
|      2 |     1 | velocity    |       30 |
|      2 |     2 | voltage     |        4 |
|      2 |     2 | temperature |       30 |
|      2 |     2 | velocity    |       31 |
+--------+-------+-------------+----------+

我想将其转换为:testId,rowId,voltage,temperature,velocity,例如:

+--------+-------+---------+-------------+----------+
| testId | rowId | voltage | temperature | velocity |
+--------+-------+---------+-------------+----------+
|      1 |     1 |       4 |          30 |       20 |
|      1 |     2 |       4 |          30 |       21 |
|      2 |     1 |       4 |          30 |       30 |
|      2 |     2 |       4 |          30 |       31 |
+--------+-------+---------+-------------+----------+

有什么想法吗?我觉得我很接近这个:

mysql> select f.testId,f.rowId,(if(f.keyName='voltage',f.keyValue,NULL)) as 'voltage',(if(f.keyName='temperature',f.keyValue,NULL)) as 'temperature',(if(f.keyName='velocity',f.keyValue,NULL)) as 'velocity' from tests t  inner join data d on t.testId = d.testId  inner join data c on t.testId = c.testId and c.rowId = d.rowId  join data f on f.testId = t.testId and f.rowId = d.rowId  where (d.keyName = 'voltage' and d.keyValue < 5) and (c.keyName = 'temperature' and c.keyValue = 30) and (t.testType = 'testType1');
+--------+-------+---------+-------------+----------+
| testId | rowId | voltage | temperature | velocity |
+--------+-------+---------+-------------+----------+
|      1 |     1 |       4 |        NULL |     NULL |
|      1 |     1 |    NULL |          30 |     NULL |
|      1 |     1 |    NULL |        NULL |       20 |
|      1 |     2 |       4 |        NULL |     NULL |
|      1 |     2 |    NULL |          30 |     NULL |
|      1 |     2 |    NULL |        NULL |       21 |
|      2 |     1 |       4 |        NULL |     NULL |
|      2 |     1 |    NULL |          30 |     NULL |
|      2 |     1 |    NULL |        NULL |       30 |
|      2 |     2 |       4 |        NULL |     NULL |
|      2 |     2 |    NULL |          30 |     NULL |
|      2 |     2 |    NULL |        NULL |       31 |
+--------+-------+---------+-------------+----------+

以下是表定义和数据源供参考:

CREATE TABLE IF NOT EXISTS `data` (
  `ptId` int(11) NOT NULL AUTO_INCREMENT,
  `testId` int(11) NOT NULL,
  `rowId` int(11) NOT NULL,
  `keyName` text NOT NULL,
  `keyValue` int(11) NOT NULL,
  PRIMARY KEY (`ptId`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=33 ;

INSERT INTO `data` (`ptId`, `testId`, `rowId`, `keyName`, `keyValue`) VALUES
(1, 1, 1, 'voltage', 4),
(2, 1, 1, 'temperature', 30),
(3, 1, 1, 'velocity', 20),
(4, 1, 2, 'voltage', 4),
(5, 1, 2, 'temperature', 30),
(6, 1, 2, 'velocity', 21),
(7, 1, 3, 'voltage', 3),
(8, 1, 3, 'temperature', 35),
(9, 1, 3, 'velocity', 22),
(10, 1, 4, 'voltage', 3),
(11, 1, 4, 'temperature', 35),
(12, 1, 4, 'velocity', 23),
(13, 2, 1, 'voltage', 4),
(14, 2, 1, 'temperature', 30),
(15, 2, 1, 'velocity', 30),
(16, 2, 2, 'voltage', 4),
(17, 2, 2, 'temperature', 30),
(18, 2, 2, 'velocity', 31),
(19, 2, 3, 'voltage', 5),
(20, 2, 3, 'temperature', 35),
(21, 2, 3, 'velocity', 32),
(22, 2, 4, 'voltage', 5),
(23, 2, 4, 'temperature', 35),
(24, 2, 4, 'velocity', 33),
(25, 4, 1, 'voltage', 4),
(26, 4, 1, 'velocity', 30),
(27, 4, 2, 'voltage', 4),
(28, 4, 2, 'velocity', 31),
(29, 4, 3, 'voltage', 5),
(30, 4, 3, 'velocity', 32),
(31, 4, 4, 'voltage', 5),
(32, 4, 4, 'velocity', 33);

CREATE TABLE IF NOT EXISTS `tests` (
  `testId` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Unique Test ID',
  `testType` text NOT NULL,
  `startDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `userName` text NOT NULL,
  `testSoftware` text NOT NULL,
  `comments` text,
  `dutID` text,
  PRIMARY KEY (`testId`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=8 ;

INSERT INTO `tests` (`testId`, `testType`, `startDate`, `userName`, `testSoftware`, `comments`, `dutID`) VALUES
(1, 'testType1', '2013-03-23 21:06:10', 'testUser1', 'testSoftware1', NULL, 'dut1'),
(2, 'testType1', '2013-03-23 21:10:32', 'testUser1', 'testSoftware1', NULL, 'dut1'),
(3, 'testType1', '2013-03-23 21:10:32', 'testUser1', 'testSoftware1', NULL, 'dut1'),
(4, 'testType2', '2013-03-23 21:10:32', 'testUser1', 'testSoftware1', NULL, 'dut1');

1 个答案:

答案 0 :(得分:1)

部分问题是您在SELECT列表中使用了聚合函数,但未使用GROUP BY。您应该使用与此类似的GROUP BY

GROUP BY d.testId, d.rowId

每当您使用聚合函数并且您的选择中有其他列时,它们应该在一个组中。所以你的完整查询应该是:

select d.testId,
  d.rowId,
  max(if(f.keyName='voltage',f.keyValue,NULL)) as 'voltage',
  max(if(f.keyName='temperature',f.keyValue,NULL)) as 'temperature',
  max(if(f.keyName='velocity',f.keyValue,NULL)) as 'velocity' 
from tests t  
inner join data d 
  on t.testId = d.testId  
inner join data c 
  on t.testId = c.testId 
  and c.rowId = d.rowId  
join data f 
  on f.testId = t.testId 
  and f.rowId = d.rowId  
where (d.keyName = 'voltage' and d.keyValue < 5) 
  and (c.keyName = 'temperature' and c.keyValue = 30) 
  and (t.testType = 'testType1')
GROUP BY d.testId, d.rowId

请注意,虽然您的实际数据结构未在原始问题中显示。看来这可以合并到以下内容:

select d.testid,
  d.rowid,
  max(case when d.keyName = 'voltage' and d.keyValue < 5 then d.keyValue end) voltage,
  max(case when d.keyName = 'temperature' and d.keyValue =30 then d.keyValue end) temperature,
  max(case when d.keyName = 'velocity' then d.keyValue end) velocity
from tests t
left join data d
  on t.testid = d.testid
group by d.testid, d.rowid

SQL Fiddle with Demo。这给结果只有一个data表的连接:

| TESTID | ROWID | VOLTAGE | TEMPERATURE | VELOCITY |
-----------------------------------------------------
|      1 |     1 |       4 |          30 |       20 |
|      1 |     2 |       4 |          30 |       21 |
|      2 |     1 |       4 |          30 |       30 |
|      2 |     2 |       4 |          30 |       31 |