doumixiang2227 2014-12-04 02:49
浏览 39

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

I have a MySQL database storing persons and their associated characteristics.

person table:

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

feature table:

+----+----------+
| id | name     |
+----+----------+
|  1 | Bravery  |
|  2 | Shyness  |
|  3 | Kindness |
|  4 | Madness  |
+----+----------+

person_features table:

+-----------+------------+-------+
| 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 |
+-----------+------------+-------+

Let's say I want the list of all the persons ordered by descending shyness, kindness and bravery (with the value of these features for each person):

+--------+---------+----------+---------+
| person | Shyness | Kindness | Bravery |
+--------+---------+----------+---------+
| Bella  | 84      | NULL     | 50      |
| Alice  | 78      | 2        | NULL    |
| Jacob  | 78      | NULL     | 8       |
| Renée  | NULL    | 64       | 36      |
| Edward | NULL    | 27       | NULL    |
+--------+---------+----------+---------+

I currently use this dynamically generated query:

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;

But it's a little slow with many features, because I must add a left join for each one. So, is there a way to use a more universal static query instead of a dynamic one? Even if it means a post-processing treatment in my PHP script to regroup data.

CREATE statements:

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;

Result of EXPLAIN:

+----+-------------+--------+--------+--------------------+---------+---------+----------------------+------+---------------------------------+
| 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 |                                 |
+----+-------------+--------+--------+--------------------+---------+---------+----------------------+------+---------------------------------+
  • 写回答

1条回答 默认 最新

  • drjmrg8766 2014-12-04 02:53
    关注

    I'm not sure if this would be faster, but you can try using conditional aggregation:

    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;
    

    Also, an index on person_features(person_id, feature_id, value) would speed up your query (as well as this one).

    评论

报告相同问题?

悬赏问题

  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测