单个查询中的MySQL项及其属性

单个查询中的MySQL项及其属性,mysql,sql,join,pivot-table,entity-attribute-value,Mysql,Sql,Join,Pivot Table,Entity Attribute Value,我创建了MySQL数据模型来存储内容及其自定义属性/字段。下面是它的简化版本 一个用于存储内容: CREATE TABLE `cms_content` ( `id` int(11) NOT NULL, `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `content_type_id` int(6) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unic

我创建了MySQL数据模型来存储内容及其自定义属性/字段。下面是它的简化版本

一个用于存储内容:

CREATE TABLE `cms_content` (
  `id` int(11) NOT NULL,
  `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `content_type_id` int(6) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

ALTER TABLE `cms_content`
  ADD PRIMARY KEY (`id`),
  ADD KEY `content_type_id` (`content_type_id`);
第二个用于内容类型(如文章、电影、人物):

自定义字段:

CREATE TABLE `cms_custom_field` (
  `id` int(11) NOT NULL,
  `name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  `content_type_id` int(6) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

ALTER TABLE `cms_custom_field`
  ADD PRIMARY KEY (`id`),
  ADD UNIQUE KEY `name` (`name`,`content_type_id`),
  ADD KEY `name_2` (`name`);
最后一个用于连接自定义字段和数据:

CREATE TABLE `cms_content_data` (
  `id` int(11) NOT NULL,
  `custom_field_id` int(11) NOT NULL,
  `content_id` int(11) NOT NULL,
  `value` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `value_content_id` int(11) DEFAULT NULL,
  `value_taxonomy_value_id` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

ALTER TABLE `cms_content_data`
  ADD PRIMARY KEY (`id`),
  ADD UNIQUE KEY `key` (`value`,`content_id`,`custom_field_id`) USING BTREE,
  ADD KEY `content_id` (`content_id`),
  ADD KEY `custom_field_id` (`custom_field_id`),
  ADD KEY `value` (`value`),
  ADD KEY `value_content_id` (`value_content_id`),
  ADD KEY `value_taxonomy_value_id` (`value_taxonomy_value_id`),
  ADD KEY `custom_field_id_2` (`custom_field_id`,`content_id`);
挑战

我需要创建一个查询来获取特定类型的内容及其所有自定义字段。 注意!这里的一个技巧是,一个自定义字段可以有多个
content\u数据
值。 例如,一部电影有一个字段
类型
,它可以在
内容\u数据
中有多行

非工作查询

我能够动态生成以下查询:

SELECT 
`content`.`id` AS `_content_id`, 
`content`.`title` AS `_content_title`, 
`content_data_0`.`value_taxonomy_value_id` AS `genres`, 
`content_data_1`.`value_content_id` AS `production_company`, 
`content_data_2`.`value` AS `date_released`, 
`content_data_3`.`value` AS `runtime`, 
`content_data_4`.`value` AS `tagline`, 
`content_data_5`.`value` AS `imdb_rating`, 
`content_data_6`.`value` AS `rt_rating`, 
`content_data_7`.`value` AS `imdb_id`, 
`content_data_8`.`value` AS `trailer_url`, 
`content_data_9`.`value` AS `api_id`, 
`content_data_10`.`value_taxonomy_value_id` AS `rating`, 
`content_data_11`.`value` AS `revenue`, 
`content_data_12`.`value` AS `poster_original_path`, 
`content_data_13`.`value` AS `rt_rating_users`, 
`content_data_14`.`value` AS `rt_url`, 
`content_data_15`.`value` AS `rt_consensus`, 
`content_data_16`.`value` AS `mc_rating`, 
`content_data_17`.`value` AS `year`, 
`content_data_18`.`value` AS `budget`, 
`content_data_19`.`value_taxonomy_value_id` AS `original_language`, 
`content_data_20`.`value_taxonomy_value_id` AS `production_countries`, 
`content_data_21`.`value` AS `original_title` 
FROM `cms_content` AS `content` 
INNER JOIN cms_content_type ON cms_content_type.id = content.content_type_id
INNER JOIN `cms_content_data` AS `content_data_0` ON `content_data_0`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_1` ON `content_data_1`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_2` ON `content_data_2`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_3` ON `content_data_3`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_4` ON `content_data_4`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_5` ON `content_data_5`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_6` ON `content_data_6`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_7` ON `content_data_7`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_8` ON `content_data_8`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_9` ON `content_data_9`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_10` ON `content_data_10`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_11` ON `content_data_11`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_12` ON `content_data_12`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_13` ON `content_data_13`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_14` ON `content_data_14`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_15` ON `content_data_15`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_16` ON `content_data_16`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_17` ON `content_data_17`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_18` ON `content_data_18`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_19` ON `content_data_19`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_20` ON `content_data_20`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_data` AS `content_data_21` ON `content_data_21`.`content_id` = `content`.`id` 
INNER JOIN `cms_content_type` AS `content_type` ON `content_type`.`id` = `content`.`content_type_id` 

WHERE `content_type`.`name` = 'movie' 
AND `content_data_0`.`custom_field_id` = 141 
AND `content_data_1`.`custom_field_id` = 143 
AND `content_data_2`.`custom_field_id` = 144 
AND `content_data_3`.`custom_field_id` = 146
AND `content_data_4`.`custom_field_id` = 148 
AND `content_data_5`.`custom_field_id` = 154 
AND `content_data_6`.`custom_field_id` = 155 
AND `content_data_7`.`custom_field_id` = 156 
AND `content_data_8`.`custom_field_id` = 158 
AND `content_data_9`.`custom_field_id` = 159 
AND `content_data_10`.`custom_field_id` = 162 
AND `content_data_11`.`custom_field_id` = 163 
AND `content_data_12`.`custom_field_id` = 164 
AND `content_data_13`.`custom_field_id` = 174 
AND `content_data_14`.`custom_field_id` = 175 
AND `content_data_15`.`custom_field_id` = 176 
AND `content_data_16`.`custom_field_id` = 177 
AND `content_data_17`.`custom_field_id` = 185 
AND `content_data_18`.`custom_field_id` = 184 
AND `content_data_19`.`custom_field_id` = 186 
AND `content_data_20`.`custom_field_id` = 187 
AND `content_data_21`.`custom_field_id` = 188 
DESC LIMIT 100
这里的问题是: 1.返回错误。显然,由于每个
content\u数据可以有多个值,MySQL以各种方式将它们组合在一起,最后我得到了一个
movie
和各种自定义字段组合。 2.查询速度非常慢(可能是因为许多联接以及字段值的组合)

问题

MySQL(当然还有一些PHP后端魔术)中有没有任何方法可以在一个查询中返回所有必需的数据?考虑到当前的数据模型

对于多行,在逗号分隔的字段值中使用值对我来说是可行的(除非有更好的方法)

或者这个数据模型只是有缺陷,我需要以某种方式对其进行更改


提前谢谢

您需要条件聚合。我认为这是:

SELECT c.id as `_content_id`, 
       c.title AS `_content_title`,
FROM content c LEFT JOIN
     (SELECT ct.content_id,
             MAX(CASE WHEN ct.custom_field_id = 141 THEN ct.value_taxonomy_value_id END as genres,
             MAX(CASE WHEN ct.custom_field_id = 143 THEN ct.value_taxonomy_value_id END as production_company,
             MAX(CASE WHEN ct.custom_field_id = 144 THEN ct.value END as date_released,
             . . .
      FROM cms_content_type ct
      GROUP BY ct.content_id
     ) ct
     ON ct.content_id = c.contentId;

注意:
value
并没有用于所有列,这似乎很奇怪。如果给定的
内容\u id
有多行,且具有相同的
客户字段\u id
,则可能需要
组\u CONCAT()。使用这种技术,需要一个连接,然后条件聚合表达式提取期望值

对于您的quer,它看起来像:

SELECT 
    c.id content_id
    c.title content_title,
    MAX(CASE WHEN d.custom_field_id = 141 THEN d.value END) genres,
    MAX(CASE WHEN d.custom_field_id = 143 THEN d.value END) production_company,
    MAX(CASE WHEN d.custom_field_id = 144 THEN d.value END) date_released
    ...
FROM cms_content c
INNER JOIN cms_content_type t ON t.id = c.content_type_id
INNER JOIN cms_content_data d ON d.content_id = c.id 
WHERE t.name = 'movie' 
GROUP BY c.id, c.title

内容真的可以有多种类型吗?什么是
value\u content\u id
value\u taxonomy\u value\u id
?@Nick 1)对一种内容类型进行一次查询2)值是自由格式文本(例如标题、正文、日期),值\u content\u id与另一种
内容相关,值\u taxonomy\u id与分类相关(例如,提供多种选择的类型)。我提出后者并不是为了简化问题。现在您可以看到EAV架构模式有多么糟糕。是的,这解决了结果问题,但查询本身仍然非常慢。即使使用了所有索引。我猜,我只需要进行第二次查询。无论如何,谢谢!是的,这解决了结果问题,但查询本身仍然非常慢。Even和所有索引。猜猜,我只需要进行第二次查询。不过谢谢你的帮助!
SELECT 
    c.id content_id
    c.title content_title,
    MAX(CASE WHEN d.custom_field_id = 141 THEN d.value END) genres,
    MAX(CASE WHEN d.custom_field_id = 143 THEN d.value END) production_company,
    MAX(CASE WHEN d.custom_field_id = 144 THEN d.value END) date_released
    ...
FROM cms_content c
INNER JOIN cms_content_type t ON t.id = c.content_type_id
INNER JOIN cms_content_data d ON d.content_id = c.id 
WHERE t.name = 'movie' 
GROUP BY c.id, c.title