[英]MySQL EAV SELECT one-to-many single row results
我在這里看過類似的問題,但是找不到符合我特定情況的問題。 我有以下三個表:
content
id, [other fields]
attributes
id, title
attributes_values
id, attribute_id[foreign to attributes.id], content_id[foreign to content.id], value
我想要的是一個單一查詢(或一組子查詢),它可以返回適當的數據,以避免在編程中操縱它。
關於表的更多信息:屬性有三個記錄(Model#,Part#和Show in Cart)。
我需要選擇來自內容的所有記錄,其中show in Cart = 1的attribute_value。除此之外,我還希望將其他相關的attribute_values作為其相關的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
到目前為止,我實現這一目標的唯一方法並不是很優雅,因為我必須對同一個表進行多次連接:
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提示),請隨意包含它。 此外,這是一個我無法改變的預先建立的表模式,因此我需要一個針對上述表的查詢解決方案,而不是更好的表設計的建議。
任何幫助將不勝感激。
干杯!
您可以使用MAX()等聚合函數與CASE WHEN語句結合使用,而不是為每個屬性多次連接表:
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
將在屬性為“Model#”時返回值,否則返回NULL
MAX(...)
將返回最大的非NULL值,這是attributes.title ='Model#'的值。
MySQL沒有Pivot函數,因此如果您希望列表是動態的,則必須使用所有屬性創建一個包含所有屬性的SQL字符串並執行此字符串。
您可以從attributes
表中獲取所有屬性:
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有一個最大長度限制 ,如果你的表持有許多屬性,你可以增加它。
請在此處查看示例小提琴。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.