Php 显示同一行项目的某些特征(位于单独的表中)

Php 显示同一行项目的某些特征(位于单独的表中),php,mysql,sql,database,Php,Mysql,Sql,Database,我有一个MySQL数据库,存储人员及其相关特征 人员表: +----+--------+ | id | name | +----+--------+ | 1 | Bella | | 2 | Jacob | | 3 | Edward | | 4 | Renée | | 5 | Alice | +----+--------+ 功能表: +----+----------+ | id | name | +----+----------+ | 1 | Bravery |

我有一个MySQL数据库,存储人员及其相关特征

人员表:

+----+--------+
| id | name   |
+----+--------+
|  1 | Bella  |
|  2 | Jacob  |
|  3 | Edward |
|  4 | Renée  |
|  5 | Alice  |
+----+--------+
功能表:

+----+----------+
| id | name     |
+----+----------+
|  1 | Bravery  |
|  2 | Shyness  |
|  3 | Kindness |
|  4 | Madness  |
+----+----------+
个人特征表:

+-----------+------------+-------+
| person_id | feature_id | value |
+-----------+------------+-------+
|         1 |          1 |    50 |
|         1 |          2 |    84 |
|         1 |          4 |    10 |
|         2 |          1 |     8 |
|         2 |          2 |    78 |
|         2 |          4 |    41 |
|         3 |          3 |    27 |
|         4 |          1 |    36 |
|         4 |          3 |    64 |
|         5 |          2 |    78 |
|         5 |          3 |     2 |
+-----------+------------+-------+
比如说,我想要所有人的名单,按羞怯、善良和幽默的降序排列 勇敢(每个人都有这些特征的价值):

我当前使用此动态生成的查询:

SELECT person.name, pf2.value, pf3.value, pf1.value
FROM person
LEFT JOIN person_features pf2 ON person.id = pf2.person_id AND pf2.feature_id = 2
LEFT JOIN person_features pf3 ON person.id = pf3.person_id AND pf3.feature_id = 3
LEFT JOIN person_features pf1 ON person.id = pf1.person_id AND pf1.feature_id = 1
ORDER BY pf2.value DESC, pf3.value DESC, pf1.value DESC, person.name;
但是它有很多特性,速度有点慢,因为我必须为每个特性添加一个左连接。那么,有没有一种方法可以使用更通用的静态查询而不是动态查询?即使这意味着在我的PHP脚本中进行后处理来重新组合数据

创建语句:

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

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

CREATE TABLE `person_features` (
  `person_id` int(11) NOT NULL,
  `feature_id` int(11) NOT NULL,
  `value` int(11) NOT NULL,
  PRIMARY KEY (`person_id`,`feature_id`),
  KEY `feature_id` (`feature_id`),
  CONSTRAINT `person_features_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `person` (`id`),
  CONSTRAINT `person_features_ibfk_2` FOREIGN KEY (`feature_id`) REFERENCES `feature` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
解释结果:

+----+-------------+--------+--------+--------------------+---------+---------+----------------------+------+---------------------------------+
| id | select_type | table  |  type  |   possible_keys    |   key   | key_len |         ref          | rows |              Extra              |
+----+-------------+--------+--------+--------------------+---------+---------+----------------------+------+---------------------------------+
|  1 | SIMPLE      | person | ALL    | NULL               | NULL    | NULL    | NULL                 |    5 | Using temporary; Using filesort |
|  1 | SIMPLE      | pf2    | eq_ref | PRIMARY,feature_id | PRIMARY | 8       | test.person.id,const |    1 |                                 |
|  1 | SIMPLE      | pf3    | eq_ref | PRIMARY,feature_id | PRIMARY | 8       | test.person.id,const |    1 |                                 |
|  1 | SIMPLE      | pf1    | eq_ref | PRIMARY,feature_id | PRIMARY | 8       | test.person.id,const |    1 |                                 |
+----+-------------+--------+--------+--------------------+---------+---------+----------------------+------+---------------------------------+

我不确定这是否会更快,但您可以尝试使用条件聚合:

select p.name,
       max(case when pf.feature_id = 2 then value end) as shyness,
       max(case when pf.feature_id = 3 then value end) as kindness,
       max(case when pf.feature_id = 1 then value end) as bravery
from person p join
     person_features pf
     on p.person_id = pf.person_id
group by p.name
order by shyness desc, kindess desc, bravery desc;

另外,在
person\u features(person\u id,feature\u id,value)
上建立一个索引会加快你的查询速度(和这个一样)。

不错,这个查询速度快了两倍,但我不确定你是否理解它。为什么要使用MAX函数?顺便说一下,索引对这两个查询没有任何更改。@doskoi。查询正在使用条件聚合来扁平化数据结构。您需要
max()
来提取每个特征的值。我很惊讶索引没有帮助。也许您在表定义中已经有了类似的索引。更优雅-但如果它实际上更快(在正确索引的数据集上),我会感到非常惊讶。这是否意味着我的无限关节查询是最优化的p@doskoi-这不是我的专业领域,但我相信是的-尽管你的“统计数据”似乎与我的“信念”相矛盾!!!我们可以看看上面的解释(和正确的DDL)吗
select p.name,
       max(case when pf.feature_id = 2 then value end) as shyness,
       max(case when pf.feature_id = 3 then value end) as kindness,
       max(case when pf.feature_id = 1 then value end) as bravery
from person p join
     person_features pf
     on p.person_id = pf.person_id
group by p.name
order by shyness desc, kindess desc, bravery desc;