0

我正在尝试针对以下问题提出一个简单、高效的查询:

假设有几个实体(项目)都有一个唯一的 ID。实体具有一组可变的属性(属性),因此已移至单独的表中:

T_Items_Props
=======================
Item_ID  Prop_ID  Value
-----------------------
101      1        'abc'
101      2        '123'
102      1        'xyz'
102      2        '123'
102      3        '102'
...      ...      ...

现在我想搜索一个匹配某些指定搜索条件的项目,如下所示:

<<Pseudo-SQL>>

SELECT Item_Id(s)
  FROM T_Items_Props
 WHERE Prop 1 = 'abc'
   AND Prop 2 = '123'
     ...
   AND Prop n = ...

如果我有一张像Items(Id, Prop_1, Prop_2, ..., Prop_n). 然后我可以做一个简单SELECT的搜索条件可以简单地(甚至以编程方式)插入 - 子句的地方WHERE,但在这种情况下,我必须做类似的事情:

SELECT t1.Item_ID
  FROM T_Items_Props t1
     , T_Items_Props t2
     , ...
     , T_Items_Props tn -- (depending on how many properties to compare)
   AND t1.Item_ID = t2.Item_ID
   AND t1.Prop_ID = 1 AND t1.Value = 'abc'
   AND t2.Prop_ID = 2 AND t2.Value = '123'
     ...
   AND tn.Prop_ID = n AND tn.Value = ...

有没有更好/更简单/更快的方法来做到这一点?

4

4 回答 4

2

为了使查询更具可读性,您可以执行以下操作:

SELECT 
    t1.Item_ID
FROM 
    T_Items_Props t1
where convert(varchar(10), t1.Item_ID) + ';' + t1.Value in (
    '1;abc',
    '2;123',
    ...
)

注意:这假设您的 ID 不会超过 10 个数字。由于额外的类型转换和字符串连接,它还可能减慢您的查询速度。

于 2013-06-13T12:58:02.233 回答
1

You could count the number of correct Props. This isn't very good in case there could be duplicates. E.g.:

Prop_ID = 1 AND Value = 'abc'
Prop_ID = 2 AND Value = '123'

and the table would look like:

T_Items_Props
=======================
Item_ID  Prop_ID  Value
-----------------------
101      1        'abc'
101      1        'abc'

this would then be true, although it shouldn't.

But if you wanna give it a try, here's how:

SELECT nested.* FROM (
SELECT item_id, count(*) AS c FROM t_items_props
WHERE ((prop = 1 AND value = 'abc')
OR (prop = 2 AND value = '123')
... more rules here ...)
GROUP BY item_id) nested
WHERE nested.c > 2 ... number of rules ...
于 2013-06-13T13:45:49.573 回答
0

我在以前的类似查询意图的帖子中提供了这个。用户一次可以有 2 个条件,另一个可以有 5 个条件,并且想要一种简单的方法来构建 SQL 命令。为了简化必须添加 FROM 表和更新 WHERE 子句的需求,您可以通过执行连接来简化并将该标准放在连接级别......因此,每个标准都是它自己的集合添加到组合中。

SELECT 
      t1.Item_ID
   FROM 
      T_Items_Props t1

         JOIN T_Items_Props t2
            on t1.Item_ID = t2.Item_ID
           AND t2.Prop_ID = 2
           AND t2.Value = '123'

         JOIN T_Items_Props t3
            on t1.Item_ID = t3.Item_ID
           AND t3.Prop_ID = 6
           AND t3.Value = 'anything'

         JOIN T_Items_Props t4
            on t1.Item_ID = t4.Item_ID
           AND t4.Prop_ID = 15
           AND t4.Value = 'another value'
   WHERE
          t1.Prop_ID = 1
      AND t1.Value = 'abc'

请注意,主查询将始终以最少的“T1”属性/值条件开始,但是,注意 JOIN 子句......它们实际上是相同的,因此很容易通过循环实现......只要保持根据需要对 T2、T3、T4 进行别名。这将从满足 T1 标准的任何项目开始,但随后也需要找到所有其余项目。

于 2013-06-13T13:09:50.950 回答
0

您可以将连接语句与过滤或分面搜索一起使用。它提供了更好的性能,因为您可以限制搜索空间。这是一个很好的例子:Faceted Search (solr) vs Good old filtering via PHP? .

于 2013-06-13T13:06:43.597 回答