2009-07-09 83 views
2

對於相當簡單的表結構,即。 Person,Criteria和Person Criteria (組合表),我已經設置了一個查詢來選擇所有擁有所有選定標準的人。高級(?)和/或查詢

本身看起來像這樣的時刻查詢:

SELECT 
    p.PersonID 
FROM 
    Person p,  
    (SELECT DISTINCT PersonID, CriteriaID 
    FROM PersonCriteria 
    WHERE CriteriaID in (#list_of_ids#)  
) k  
WHERE 
    p.PersonID= k.PersonID  
GROUP BY 
    p.PersonID  
HAVING 
    Count(*) = #Listlength of list_of_ids# 

到目前爲止,沒有任何問題,一切工作正常。

現在我想提供給用戶的可能性增加一些AND和OR變量在他們的搜索,即。有人可能會說:

我正在尋找的是擁有人:標準1和3和4 AND(5或6或7),(8或9(這將通過上面的查詢被覆蓋) )等等...

我不確定從哪裏開始增加這個級別。我希望別人做.. :-)

回答

2

我不得不說 - 我很爲難。我想不出任何即將接近的解決方案。我會嘗試尋找這些方向上的解決方案:

  • 用戶定義的集合函數。也許你可以創建一個函數,將所需表達式(以簡化語法)和單個行的行作爲參數。該函數然後解析表達式並將其與行進行匹配。嗯...也許MySQL包括一些串聯聚合函數和正則表達式匹配函數?這可能是一個解決方案(雖然可能不是一個非常快的)。
  • 分析功能。我不假裝我理解他們,但儘管我對他們瞭解得多,但我認爲他們一般都在這個方向。雖然我不知道是否會有適合這種需求的功能。

補充: 啊,我想我明白了!雖然我認爲表演會很悲慘。但這會奏效!舉例來說,如果你要搜索1 AND 2 AND (3 OR 4)的要求,那麼你可以這樣寫:

SELECT 
    * 
FROM 
    Persons A 
WHERE 
    EXISTS (Select * from PersonCriteria B WHERE A.PersonID=B.PersonID AND CriteriaID=1) 
    AND 
    EXISTS (Select * from PersonCriteria B WHERE A.PersonID=B.PersonID AND CriteriaID=2) 
    AND 
    (
     EXISTS (Select * from PersonCriteria B WHERE A.PersonID=B.PersonID AND CriteriaID=3) 
     OR 
     EXISTS (Select * from PersonCriteria B WHERE A.PersonID=B.PersonID AND CriteriaID=4) 
    ) 

新增2:這裏有一個又一個,但性能可能會更差:

SELECT p.* FROM Person p 
    JOIN (select PersonID from PersonCriteria WHERE CriteriaID=1) c1 ON p.PersonID=c1.PersonID 
    JOIN (select PersonID from PersonCriteria WHERE CriteriaID=2) c2 ON p.PersonID=c2.PersonID 
    JOIN (select PersonID from PersonCriteria WHERE CriteriaID IN (3,4)) c3 ON p.PersonID=c3.PersonID 

添加3:這是2號的變體,但實際上這可能會有一個體面的表現!

SELECT p.* FROM 
    Person p 
    JOIN PersonCriteria c1 on (p.PersonID=c1.PersonID AND c1.CriteriaID=1) 
    JOIN PersonCriteria c2 on (p.PersonID=c2.PersonID AND c2.CriteriaID=2) 
    JOIN PersonCriteria c3 on (p.PersonID=c3.PersonID AND c3.CriteriaID IN (3,4)) 

如果添加索引的列PersonCriteria(是PersonID,CriteriaID)(正是在這個順序!),那麼我認爲這是關於一樣快,你要在任何情況下得到的。

+0

你的號碼「3」很好地訣竅。我必須添加不同的選擇,性能似乎並不太糟糕。 謝謝! – 2009-07-10 08:41:06

+0

是的,我忘了DISTINCT部分。 :) – 2009-07-10 08:48:31

1

您可以通過執行簡化這個了很多,比如:

SELECT DISTINCT PERSONID FROM PersonCriteria WHERE CriteriaID IN(1,2)OR CriteriaID IN(8,9)

還要考慮使用JOIN的,而不是子查詢(性能)

+0

我想你錯過了這一點。重新閱讀並認真思考...... – 2009-07-09 21:12:38

1

我明白你問這是否應該工作。我不能保證我明白你在問什麼,但很明顯,有幾個人已經有了不同的解釋。

SELECT p.PersonID 
FROM Person p 
JOIN  
(SELECT DISTINCT PersonID  
FROM PersonCriteria  
WHERE CriteriaID in (1,2,3) and count(criteriaID) = 3) k 
     on p.PersonID = k.PersonID 
JOIN 
    (SELECT DISTINCT PersonID  
FROM PersonCriteria  
WHERE CriteriaID in (4,5)) k2 on p.PersonID = k2.PersonID 
JOIN 
    (SELECT DISTINCT PersonID  
FROM PersonCriteria  
WHERE CriteriaID in (5,6,7)) k3 on p.PersonID = k3.PersonID 
JOIN 
    (SELECT DISTINCT PersonID  
FROM PersonCriteria  
WHERE CriteriaID in (8,9)) k4 on p.PersonID = k4.PersonID 

我是這樣解釋的。第一次連接是派生表,獲取具有全部三個指定條件的任何人。後續派生表通過加入其餘派生表來查找滿足這些條件之一(基本上是OR部分)的人,我們完成查詢的AND部分。我也知道語法通過SQL Server的語法檢查,它可能需要調整MYSQL。

0

如果您需要提供一個更「動態」的辦法來搜索數據時,SQL會得到真正的醜陋,長,不會真的是完全動態的,......我提到「醜」?

我對任務使用ORM框架,他們處理工作很棒。

但是,如果你的結構是隻爲你描述(帶或包裹很多AND條件),那麼假設你目前的和唯一的實現是在一個UDF叫dbo.getPersonForAndCriteria(...),你可以實現,或者乾脆利用UNION

dbo.getPersonForAndCriteria(@myListOfIDs1) --// works for AND 
UNION -- replaces OR 
dbo.getPersonForAndCriteria(@myListOfIDs2) --// works for AND 
UNION -- replaces OR 
dbo.getPersonForAndCriteria(@myListOfIDs3) --// works for AND 

注意:這只是說明性的,但我會將你的過程包裝成一個很好的UDF,它將參數列表(ID)作爲一個表格(使用XML或逗號分隔的字符串,然後在UDF中進行解析) ,然後在這個列表/表格上做一個很好的JOIN,而不是WHERE ... IN部分,最後一部分變爲COUNT(*)= COUNT(SELECT ID FROM myFilterTable)。