MySQL EAV SELECT一对多单行结果
MySQL EAV SELECT one-to-many single row results
我在这里看到过类似的问题,但没能找到符合我的具体情况的问题。我有以下三个 tables:
content
id, [other fields]
attributes
id, title
attributes_values
id, attribute_id[foreign to attributes.id], content_id[foreign to content.id], value
我想要的是单个查询(或一组子查询),它可以 return 适当的数据以避免在编程中必须对其进行操作。
关于 tables 的更多信息:属性有三个记录(型号 #、零件 # 和在购物车中显示)。
我需要 select 来自 attribute_value 在购物车中显示 = 1 的内容的所有记录。除此之外,我希望其他相关的 attribute_value 是return编辑为他们的相关 attribute.title。结果看起来像这样:
id [other fields] Model # [from attributes.title field] Part # [from attributes.title field]
1 [any data] value from attributes_values value from attributes_values
2 [any data] value from attributes_values value from attributes_value
到目前为止,我完成此操作的唯一方法不是很优雅,因为我必须对同一个 table:
进行多次连接
SELECT * FROM content AS a
LEFT JOIN attributes_values AS b ON (b.content_id = a.id AND b.attribute_id = [Model # ID])
LEFT JOIN attributes_values AS c ON (c.content_id = a.id AND c.attribute_id = [Part # ID])
WHERE a.id IN (
SELECT content_id FROM attributes_values WHERE attribute_id = [Show in Cart ID] AND value = 1
)
如您所见,我不得不将相关键硬编码到 JOIN 语句中,这不会使其具有很好的可扩展性(而且感觉很脏)。
一些最后的注意事项:我正在使用 PHP 和 Joomla!,所以如果这会影响您的回答(或者如果有一些秘密的 Joomla 提示),请随时包含它。此外,这是我无法更改的预先建立的 table 模式,因此我需要针对上述 table 的查询解决方案,而不是关于更好的 table 的建议] 设计.
任何帮助将不胜感激。
干杯!
您可以将 MAX() 等聚合函数与 CASE WHEN 语句结合使用,而不是为每个属性多次加入 table:
SELECT
content.id,
[other_fields],
MAX(CASE WHEN attributes.title='Model #' THEN attributes_values.value END) AS Model_N,
MAX(CASE WHEN attributes.title='Part #' THEN attributes_values.value END) AS Part_N
FROM
content INNER JOIN attributes_values
ON content.id = attributes_values.content_id
INNER JOIN attributes
ON attributes_values.attribute_id = attributes.id
GROUP BY
id,
[other_fields]
HAVING
MAX(CASE WHEN attributes.title='Show in Cart' THEN attribute_values.value END)='1'
一点解释:
CASE WHEN attributes.title='Model #' THEN attributes.value END
将 return 属性为 'Model #' 时的值,否则为 NULL,并且
MAX(...)
将return最大非NULL值,也就是attributes.title='Model #'.
的值
动态属性
MySQL 没有 Pivot 函数,所以如果你想让你的列表是动态的,你必须动态地创建一个包含所有属性的 SQL 字符串并执行这个字符串。
您可以从 attributes
table:
中获取所有属性
SELECT
CONCAT(
'MAX(CASE WHEN attributes.title=''',
REPLACE(attributes.title, '''', ''''''),
''' THEN attributes_values.value END) AS `',
REPLACE(attributes.title, '`', '``'),
'`'
)
FROM
attributes;
并将所有内容与 GROUP_CONCAT 组合在一起:
SELECT GROUP_CONCAT(...the concat above...)
FROM attributes;
所以你的最终查询将是这样的:
SELECT
CONCAT('SELECT content.id,',
GROUP_CONCAT(
CONCAT(
'MAX(CASE WHEN attributes.title=''',
REPLACE(attributes.title, '''', ''''''),
''' THEN attributes_values.value END) AS `',
REPLACE(attributes.title, '`', '``'),
'`'
)
),
' FROM content INNER JOIN attributes_values ',
'ON content.id = attributes_values.content_id ',
'INNER JOIN attributes ',
'ON attributes_values.attribute_id = attributes.id ',
'GROUP BY id HAVING ',
'MAX(CASE WHEN attributes.title=''Show in Cart'' THEN attributes_values.value END)=''1'''
)
FROM
attributes
INTO @SQL;
现在,@SQL 变量将保存要执行的查询的值,您可以执行它:
PREPARE stmt FROM @sql;
EXECUTE stmt;
这里唯一的问题是 GROUP_CONCAT 有一个 maximum length limit,如果你的 table 有很多属性,你可以增加它。
请看例子fiddle here.
我在这里看到过类似的问题,但没能找到符合我的具体情况的问题。我有以下三个 tables:
content
id, [other fields]
attributes
id, title
attributes_values
id, attribute_id[foreign to attributes.id], content_id[foreign to content.id], value
我想要的是单个查询(或一组子查询),它可以 return 适当的数据以避免在编程中必须对其进行操作。
关于 tables 的更多信息:属性有三个记录(型号 #、零件 # 和在购物车中显示)。
我需要 select 来自 attribute_value 在购物车中显示 = 1 的内容的所有记录。除此之外,我希望其他相关的 attribute_value 是return编辑为他们的相关 attribute.title。结果看起来像这样:
id [other fields] Model # [from attributes.title field] Part # [from attributes.title field]
1 [any data] value from attributes_values value from attributes_values
2 [any data] value from attributes_values value from attributes_value
到目前为止,我完成此操作的唯一方法不是很优雅,因为我必须对同一个 table:
进行多次连接SELECT * FROM content AS a
LEFT JOIN attributes_values AS b ON (b.content_id = a.id AND b.attribute_id = [Model # ID])
LEFT JOIN attributes_values AS c ON (c.content_id = a.id AND c.attribute_id = [Part # ID])
WHERE a.id IN (
SELECT content_id FROM attributes_values WHERE attribute_id = [Show in Cart ID] AND value = 1
)
如您所见,我不得不将相关键硬编码到 JOIN 语句中,这不会使其具有很好的可扩展性(而且感觉很脏)。
一些最后的注意事项:我正在使用 PHP 和 Joomla!,所以如果这会影响您的回答(或者如果有一些秘密的 Joomla 提示),请随时包含它。此外,这是我无法更改的预先建立的 table 模式,因此我需要针对上述 table 的查询解决方案,而不是关于更好的 table 的建议] 设计.
任何帮助将不胜感激。
干杯!
您可以将 MAX() 等聚合函数与 CASE WHEN 语句结合使用,而不是为每个属性多次加入 table:
SELECT
content.id,
[other_fields],
MAX(CASE WHEN attributes.title='Model #' THEN attributes_values.value END) AS Model_N,
MAX(CASE WHEN attributes.title='Part #' THEN attributes_values.value END) AS Part_N
FROM
content INNER JOIN attributes_values
ON content.id = attributes_values.content_id
INNER JOIN attributes
ON attributes_values.attribute_id = attributes.id
GROUP BY
id,
[other_fields]
HAVING
MAX(CASE WHEN attributes.title='Show in Cart' THEN attribute_values.value END)='1'
一点解释:
CASE WHEN attributes.title='Model #' THEN attributes.value END
将 return 属性为 'Model #' 时的值,否则为 NULL,并且
MAX(...)
将return最大非NULL值,也就是attributes.title='Model #'.
的值动态属性
MySQL 没有 Pivot 函数,所以如果你想让你的列表是动态的,你必须动态地创建一个包含所有属性的 SQL 字符串并执行这个字符串。
您可以从 attributes
table:
SELECT
CONCAT(
'MAX(CASE WHEN attributes.title=''',
REPLACE(attributes.title, '''', ''''''),
''' THEN attributes_values.value END) AS `',
REPLACE(attributes.title, '`', '``'),
'`'
)
FROM
attributes;
并将所有内容与 GROUP_CONCAT 组合在一起:
SELECT GROUP_CONCAT(...the concat above...)
FROM attributes;
所以你的最终查询将是这样的:
SELECT
CONCAT('SELECT content.id,',
GROUP_CONCAT(
CONCAT(
'MAX(CASE WHEN attributes.title=''',
REPLACE(attributes.title, '''', ''''''),
''' THEN attributes_values.value END) AS `',
REPLACE(attributes.title, '`', '``'),
'`'
)
),
' FROM content INNER JOIN attributes_values ',
'ON content.id = attributes_values.content_id ',
'INNER JOIN attributes ',
'ON attributes_values.attribute_id = attributes.id ',
'GROUP BY id HAVING ',
'MAX(CASE WHEN attributes.title=''Show in Cart'' THEN attributes_values.value END)=''1'''
)
FROM
attributes
INTO @SQL;
现在,@SQL 变量将保存要执行的查询的值,您可以执行它:
PREPARE stmt FROM @sql;
EXECUTE stmt;
这里唯一的问题是 GROUP_CONCAT 有一个 maximum length limit,如果你的 table 有很多属性,你可以增加它。
请看例子fiddle here.