高级(?)和/或查询

时间:2009-07-09 20:59:37

标签: sql mysql

对于非常简单的表结构,即。人,标准和人标准 (组合表),我现在设置了一个查询,选择所有拥有所有选定标准的人。

此时查询本身看起来像这样:

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的人   (将由上述查询涵盖)和(5 OR 6或7)和(8或9)等等...

我不知道从哪个附加级别开始。我希望别人能做.. :-)

4 个答案:

答案 0 :(得分: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))

如果你在列(PersonID,CriteriaID)上添加一个索引给PersonCriteria(完全按照这个顺序!),那么我认为它的速度和你在任何情况下的速度一样快。

答案 1 :(得分:1)

您可以对此进行简化,例如:

SELECT DISTINCT 是PersonID 来自PersonCriteria 哪里 CriteriaID IN(1,2)OR CriteriaID IN(8,9)

还考虑使用JOIN而不是子选择(用于性能)

答案 2 :(得分: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。

答案 3 :(得分:0)

如果你需要提供一种更“动态”的方法来搜索你的数据,那么SQL会变得非常丑陋和冗长,并且不会真正完全动态......我是否提到“丑陋”?

我使用ORM框架完成任务,他们处理的工作非常棒。

但是如果您的结构只是如您所描述的那样(使用OR包装许多AND条件),那么假设您当前的AND-only实现位于名为dbo.getPersonForAndCriteria(...)的UDF中,您可以简单地使用{{ 1}}:

UNION

注意:这只是说明性的,但我会将您的过程包装成一个好的UDF,它将参数列表(ID)作为一个表(使用XML或逗号分隔的字符串,然后在UDF中解析),然后在这个列表/表上而不是dbo.getPersonForAndCriteria(@myListOfIDs1) --// works for AND UNION -- replaces OR dbo.getPersonForAndCriteria(@myListOfIDs2) --// works for AND UNION -- replaces OR dbo.getPersonForAndCriteria(@myListOfIDs3) --// works for AND 部分做一个很好的JOIN,最后一部分变成COUNT(*)= COUNT(SELECT ID FROM myFilterTable)。