4

我有一个高级搜索表单,它提供了多种过滤搜索的方法。这是一个简化的想法(不包括关键字文本输入或日期范围搜索或其他选择菜单):

Topic: 
<select><option>any</option><option>all</option></select>
[] Aging
[] Environment
[] Health
[] Hunger
[] Poverty

Document type: 
<select><option>any</option><option>all</option></select>
[] Case Study
[] Policy Brief
[] Whitepaper

如果有人在选择多个主题或文档类型时选择“任何”,则查询需要包括,例如,主题 =“老化”主题 =“健康”。

如果有人在选择多个主题或文档类型时选择“全部”,则查询需要包括,例如,主题 =“老化”主题 =“健康”。

我们默认在这些不同的过滤器之间使用“AND”。因此,当您搜索归类为 Aging 的所有文档以及归类为白皮书的所有文档时,查询为:topic = "Aging" AND doctype = "whitepaper"。

问题:当搜索“任何”时,我们有一个查询有效。但是当搜索“all”时,根据 MySQL 的“EXPLAIN”命令,我们有一个“不可能的 WHERE”。:(

以下是当有人为主题和文档类型选择“任何”时有效的查询:

SELECT 
DISTINCT * 
FROM research 
JOIN link_resource_doctype ON link_resource_doctype.resource_id = research.research_id 
JOIN doctype ON doctype.id = link_resource_doctype.doctype_id 
JOIN link_resource_issue_area ON link_resource_issue_area.resource_id = research.research_id 
JOIN issue_area ON issue_area.id = link_resource_issue_area.issue_area_id 
WHERE approved = '1' 
AND (doctype.identifier = 'case_study' OR doctype.identifier = 'whitepaper') 
AND (issue_area.identifier = 'aging' OR issue_area.identifier = 'health')

是相同的查询,当有人为主题和文档类型选择“全部”时,它不起作用(如果有人只选择主题或文档类型,这也不起作用):

SELECT 
DISTINCT * 
FROM research 
JOIN link_resource_doctype ON link_resource_doctype.resource_id = research.research_id 
JOIN doctype ON doctype.id = link_resource_doctype.doctype_id 
JOIN link_resource_issue_area ON link_resource_issue_area.resource_id = research.research_id 
JOIN issue_area ON issue_area.id = link_resource_issue_area.issue_area_id 
WHERE approved = '1' 
AND (doctype.identifier = 'case_study' AND doctype.identifier = 'whitepaper') 
AND (issue_area.identifier = 'aging' AND issue_area.identifier = 'health')

可能的解决方案,但有一个问题:我在 Stackoverflow 上看到了这篇文章——选择属于多个类别的行——其中包含一个查询,我认为当有人选择“全部”时可能会解决我们的问题。这里是:

SELECT 
DISTINCT * 
FROM research 
JOIN link_issue_area ON link_issue_area.resource_id = research.research_id 
JOIN link_doctype ON link_doctype.resource_id = research.research_id 
WHERE issue_area.identifier IN ('aging', 'health')
AND 
doctype_id.identifier IN ('case_study', 'whitepaper')
GROUP BY research.research_id
HAVING COUNT(DISTINCT issue_area.identifier) = 2 
AND 
COUNT(DISTINCT doctype.identifier) = 2

问题:这个查询似乎对“任何”或“全部”都有效,除了一个问题。假设文档归类为老化、健康和贫困,但搜索的人只勾选了老化和健康。被勾选的两个主题和未勾选的 Poverty 分类下的文档不会出现在搜索结果列表中。我认为这是因为 HAVING COUNT (DISTINCT issue_area.identifier) = 2 - 2 不包括任何实际具有大于 2 的 COUNT 的文档。有解决方法吗?或者在这里使用更好的查询?

非常感谢任何见解,想法,帮助!谢谢!

这是一个 SQLfiddle,它也能做到这一点:http ://sqlfiddle.com/#!2/847362/1

4

2 回答 2

0

我不太明白这个问题,因为您没有显示预期的输出。但据我了解,这是我迄今为止所做的。请评论是什么错误:

可能的解决方案,但可能有效:

SELECT   research.research_id AS resource_id, research.title
FROM     research
JOIN     link_issue_area ON link_issue_area.resource_id = research.research_id
JOIN     link_doctype ON link_doctype.resource_id = research.research_id
JOIN (SELECT resource_id, COUNT(DISTINCT issue_area_id) AS ISSUE_COUNT FROM link_issue_area
      GROUP BY resource_id) TB1_COUNT ON TB1_COUNT.resource_id = research.research_id
JOIN (SELECT resource_id, COUNT(DISTINCT doctype_id) AS DOCTYPE_COUNT FROM link_doctype
     GROUP BY resource_id) TB2_COUNT ON TB2_COUNT.resource_id = research.research_id
WHERE    issue_area_id IN (5,10)
AND       doctype_id IN (3,18)
AND   TB1_COUNT.ISSUE_COUNT = 2
AND TB2_COUNT.DOCTYPE_COUNT = 2
GROUP BY resource_id
LIMIT 0,1

这是SQLFiddle

于 2013-09-04T22:45:47.583 回答
0

来自 SQLFiddle 的现有查询几乎就是您所需要的,只要您只在需要所有选项的地方动态包含 HAVING 条件。像这样:

SELECT   research.research_id AS resource_id, research.title 
FROM     research 
JOIN     link_issue_area ON link_issue_area.resource_id = research.research_id 
JOIN     link_doctype ON link_doctype.resource_id = research.research_id 
WHERE    issue_area_id IN (5,10) /* dynamically-generated list of issues */
  AND    doctype_id IN (3,18) /* dynamically-generated list of doc types */
GROUP BY resource_id
HAVING 1=1
  AND    COUNT(DISTINCT issue_area_id) = 2 /* dynamically-generated count of
      user-selected issues - only included when all specified issues required */
  AND    COUNT(DISTINCT doctype_id) = 2 /* dynamically-generated count of
      user-selected doc types - only included when all specified types required*/

包含虚拟条件1=1意味着您始终可以包含 HAVING 子句,即使没有任何选项是all.

因此,您动态生成的查询以返回具有所有问题 5 和 10 以及所有文档类型 3 和 18 的资源,如下所示:

SELECT   research.research_id AS resource_id, research.title 
FROM     research 
JOIN     link_issue_area ON link_issue_area.resource_id = research.research_id 
JOIN     link_doctype ON link_doctype.resource_id = research.research_id 
WHERE    issue_area_id IN (5,10)
  AND    doctype_id IN (3,18)
GROUP BY resource_id
HAVING 1=1
  AND    COUNT(DISTINCT issue_area_id) = 2
  AND    COUNT(DISTINCT doctype_id) = 2

SQLFiddle在这里

虽然返回具有任何问题 10 和 20 以及任何文档类型 15 和 18 的资源的动态生成查询如下所示:

SELECT   research.research_id AS resource_id, research.title 
FROM     research 
JOIN     link_issue_area ON link_issue_area.resource_id = research.research_id 
JOIN     link_doctype ON link_doctype.resource_id = research.research_id 
WHERE    issue_area_id IN (10,20)
  AND    doctype_id IN (15,18)
GROUP BY resource_id
HAVING 1=1

SQLFiddle在这里

于 2013-09-05T20:02:07.450 回答