网站存储有关大量项目的所有规格的信息,并通过在前端添加一些过滤条件,为用户提供搜索数据的能力。在后端,所有条件都被转换为子句,并由AND
操作数连接。
我的目的是让用户知道每个过滤器后丢弃或丢弃的商品数量。确切的数字对于初始筛分不是很重要(一些模糊或近似很好,因为整个数量非常大),但在后期阶段,当剩下十个左右的项目时,用户应该得到适当的数量。
有明显直接的方式来制作尽可能多的SELECT COUNT
查询,因为他有过滤器,但我觉得可能是一种技术以更优雅的方式存档它并且不会滥用DB。
答案 0 :(得分:1)
有很多方法可以通过不同程度的难度和性能实现这一目标。
对我来说,第一个也是最明显的方法是简单地对过滤器进行计数,这些过滤器表现相当不错并且难以实现。另一种类似的方法是按值进行分组并进行计数。
这里有一个小提琴作为两种方法的例子:http://sqlfiddle.com/#!15/0cdcb/26
select
count(product.id) total,
sum((v0.value = 'spam')::int) v0_is_spam,
sum((v0.value != 'spam')::int) v0_not_spam,
sum((v1.value = 'spam')::int) v1_is_spam,
sum((v1.value != 'spam')::int) v1_not_spam
from product
left join specification_value v0 on v0.product_id = product.id and v0.specification_id = 1
left join specification_value v1 on v1.product_id = product.id and v1.specification_id = 2;
select specification.id, value, count(*)
from specification
left join specification_value on specification.id = specification_value.specification_id
group by specification.id, value;
执行类似操作的一种稍微困难的方法是使用窗口函数,更灵活但不易掌握。文档在这里:http://www.postgresql.org/docs/9.3/static/tutorial-window.html
示例查询和结果:
SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary;
depname | empno | salary | avg
-----------+-------+--------+-----------------------
develop | 11 | 5200 | 5020.0000000000000000
develop | 7 | 4200 | 5020.0000000000000000
develop | 9 | 4500 | 5020.0000000000000000
develop | 8 | 6000 | 5020.0000000000000000
develop | 10 | 5200 | 5020.0000000000000000
personnel | 5 | 3500 | 3700.0000000000000000
personnel | 2 | 3900 | 3700.0000000000000000
sales | 3 | 4800 | 4866.6666666666666667
sales | 1 | 5000 | 4866.6666666666666667
sales | 4 | 4800 | 4866.6666666666666667
(10 rows)
最后,到目前为止最快但也最不准确且难以实施。使用数据库统计信息来猜测行数。我不会选择这个,除非你在过滤器集中有数百万行,并且无法进一步减少它。此外,除非表现非常糟糕,否则不要这样做。