我正在尝试针对以下问题提出一个简单,高效的查询:
假设有几个实体(项目)都具有唯一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 = ...
有更好/更简单/更快的方法吗?
答案 0 :(得分: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个digets。由于额外的类型转换和字符串连接,它也可能会降低查询速度。
答案 1 :(得分:1)
您可以计算正确道具的数量。如果可能存在重复,这不是很好。 E.g:
Prop_ID = 1 AND Value = 'abc'
Prop_ID = 2 AND Value = '123'
,表格如下:
T_Items_Props
=======================
Item_ID Prop_ID Value
-----------------------
101 1 'abc'
101 1 'abc'
这将是真的,虽然它不应该。
但是,如果你想尝试一下,这是如何:
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 ...
答案 2 :(得分:0)
您可以将join语句与过滤或分面搜索结合使用。它提供了更好的性能,因为您可以限制搜索空间。这是一个很好的例子:Faceted Search (solr) vs Good old filtering via PHP?。
答案 3 :(得分: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标准的任何项目开始,但也需要找到所有其余项目。