簡體   English   中英

MySQL構造此查詢的最佳方法?

[英]MySQL best way to construct this query?

我繼承了一個數據庫,該數據庫的結構包含一個產品表,一個由某些產品屬性組成的表以及另一個用於在這些屬性與給定產品之間建立關系的表。

用戶可以通過這些屬性的組合來過濾產品,這意味着如果選擇了多個屬性,則僅返回具有所有這些屬性的產品。 不幸的是,該規則現在有一個例外,即選擇兩個特定屬性之一的用戶需要包含其中一個(或兩個)的結果。

查詢當前看起來像這樣(不是我的代碼):

SELECT DISTINCT p.* FROM products AS p 
INNER JOIN attributes a ON p.product_id=a.property_id 
WHERE a.attribute_id IN (1,3,7) 
GROUP BY p.property_id 
HAVING COUNT(DISTINCT a.attribute_id) = 3 

我懷疑以上內容是檢索所需產品的特別有效的方法,但是我不確定如何根據新要求進行操作。

現在,當選擇了兩個“特殊”屬性(3和7)時,我已經創建了一些php代碼來構造一個特殊的查詢:

SELECT DISTINCT p.* FROM products AS p 
INNER JOIN attributes a ON p.product_id=a.property_id 
WHERE a.attribute_id IN (1,3) OR a.attribute_id IN (1,7) 
GROUP BY p.property_id 
HAVING COUNT(DISTINCT a.attribute_id) = 2

但是,這仍然無法按要求工作-共享這兩個屬性的任何產品都不會返回結果中(這顯然是由於HAVING COUNT子句引起的,但我不知道如何解決它。為了清楚起見,問題是,如果10個產品僅具有屬性3,而另外五個具有屬性3和7,則上述查詢將僅返回10條記錄。

可能可以使用某種子查詢,或者有哪些替代方法?

該查詢看起來不錯,但是您可以刪除DISTINCT修飾符,因為您已經按ID進行了分組。 關於新要求,您能否在到達SQL查詢之前在代碼中解決它?

編輯:一種替代方法是使用每個所需屬性的一個內部聯接構造查詢,但這可能會慢得多

我認為看起來已經不錯。 除了強制性的“不要選擇*”外,對我來說還可以。

我的建議:如果它可以正常工作並且不引起性能問題,請將其留在其他地方。 如果將來出現問題,請重新訪問。

這是執行原始查詢的更好方法:

SELECT ... FROM products AS p 
INNER JOIN attributes a1 ON p.product_id=a1.property_id AND a1.attribute_id=1
INNER JOIN attributes a2 ON p.product_id=a2.property_id AND a2.attribute_id=3
INNER JOIN attributes a3 ON p.product_id=a3.property_id AND a3.attribute_id=7

並且,假設您需要attribute_id 3,則需要將其與attribute_id 7進行“或”運算,並假設還需要attribute_id 1,這不是那些特殊屬性之一:

SELECT ... FROM products AS p 
INNER JOIN attributes a1 ON p.product_id=a1.property_id AND a1.attribute_id=1
LEFT OUTER JOIN attributes a2 ON p.product_id=a2.property_id AND a2.attribute_id=3
LEFT OUTER JOIN attributes a3 ON p.product_id=a3.property_id AND a3.attribute_id=7
WHERE a2.attribute_id IS NOT NULL OR a3.attribute_id IS NOT NULL

我懷疑這些方法中的任何一個都將比具有單獨/具有/按匯總操作分組的原始方法快得多。 屬性表應該在(property_id,attribute_id)或(attribute_id,property_id)上都具有多列唯一索引,盡管我認為property_id具有更高的選擇性,因此應該是索引中最左邊的列。

有了適當的(顯而易見的)索引,在MySQL中這將非常有效。

選擇 ...

從產品AS p

INNER JOIN屬性a1 ON p.product_id = a1.property_id AND a1.attribute_id = 1
左聯接屬性a2 ON p.product_id = a2.property_id和a2.attribute_id = 3
左聯接屬性a3 ON p.product_id = a3.property_id和a3.attribute_id = 7

在哪里(
當a1.product_attribute_id為NULL則為0,否則為1結束
+當a1.product_attribute_id為NULL則為0,否則為1結束
)> 0

如何選擇p。*並僅按1列分組? 還是可以使用主鍵?

其中a1.attribute_id IN(1,3)或a1.attribute_id IN(1,7)

是相同的

在哪里a1.attribute_id IN(1、3、7)

SELECT p.* FROM products  
INNER JOIN (
    SELECT a1.property_id  
    FROM attributes a1 
    WHERE a1.attribute_id IN (1,3,7)
    GROUP BY a1.property_id 
    HAVING COUNT(DISTINCT a1.attribute_id) = 2
) as a ON p.product_id=a.property_id

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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