簡體   English   中英

MySQL EAV SELECT一對多單行結果

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM