我需要在网站上搜索功能,其中您应该能够选择多个类别。搜索将存储在数据库中,但每个唯一的搜索参数组合只应存储一次,这也包括所选类别的唯一组合。
问题在于我无法弄清楚如何存储所选类别的组合。我查看了数组并找到了这个http://blog.2ndquadrant.com/postgresql-9-3-development-array-element-foreign-keys/,但显然该功能从未实现过。
因此,如果我需要使用多个表,我想我可以有一个表,用于组合,每个唯一组合的id可以被引用和比较,然后另一个表将类别链接到组合。但是使用这种方法,我如何检查组合是否已经存在?我能想到的唯一方法是循环遍历所有现有组合,并检查其中任何一个组合是否等于比较组合。
我觉得这不是一个不常见的问题,但我找不到任何这样做的例子。我也觉得我的方法可能不是最好的。任何建议都非常受欢迎。
I have these two tables currently:
Categories
- CategoryId (int)
- Name (string)
Searches
- SearchId (int)
- Keywords (string)
- ExampleOption1 (bool)
- ExampleOption2 (bool)
- CategoriesCombinationId (int) -- this would represent the unique combination of categories and links to the combination table
这就是我尝试解决问题的方法(如果有一种很好的方法来检查组合是否已经存在):
CategoriesCombinations -- unique combinations
- CombinationId (int)
CombinedCategories
- CombinationId (int) -- links to id in combinations table
- CategoryId (int) -- links to id in categories table
答案 0 :(得分:0)
对于您当前的方法,您可以使用string_agg
在每个Categories
中包含所有CategoriesCombinations
的字符串表示形式,并针对新搜索进行检查:
SELECT CombinationId
FROM CombinedCategories
WHERE string_agg(CategoryId, ',') = '84,95,102'
GROUP BY CombinationId
但更简单的方法是根据所有参数计算每次搜索的唯一哈希值,并将其存储在Searches
表中,并将新搜索的哈希值与搜索历史记录进行比较。
答案 1 :(得分:0)
我会考虑提供方便(和快速)功能uniq()
和sort()
的附加模块intarray。在典型的现代Postgres安装中,它很简单:
CREATE EXTENSION intarray;
使用这些,一个简单的CHECK
约束可以使用不同的元素强制执行升序数组。
CHECK (uniq(sort(cat_arr)) = cat_arr)
您可以另外(可选)拥有一个自动规范化数组值ON INSERT OR UPDATE
的触发器。然后你可以传递任何数组(可能是未分类的和带有dupes),一切正常。像:
CREATE OR REPLACE FUNCTION trg_search_insup_bef()
RETURNS trigger AS
$func$
BEGIN
NEW.cat_arr := uniq(sort(NEW.cat_arr);
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
CREATE TRIGGER insup_bef
BEFORE INSERT OR UPDATE OF cat_arr ON search
FOR EACH ROW
EXECUTE PROCEDURE trg_search_insup_bef();
附加模块intarray是可选的,还有其他方法:
但是inarray功能提供了卓越的性能。
然后您可以在数组列上创建 UNIQUE
约束,以强制整个数组的唯一性。
UNIQUE (cat_arr)
我在两天前的相关答案中写了更多关于(非常严格和可靠)约束与(不太可靠但更方便)触发器的优点:
如果,对于每种组合,您需要为每个类别存储的是ID(并且没有其他信息),这应该足够了。
但是,这种方式不容易确保参照完整性。数组元素没有外键约束(尚未) - 如documented in your link:如果其中一个类别被删除或您更改了ID,引用就会中断......
如果您需要存储更多内容,或者您更愿意使用规范化架构来强制参照完整性或出于某种原因,您也可以这样做,并添加触发器以填充手工制作的物化视图(冗余表)并以类似的方式强制执行唯一性:
CREATE TABLE search (
search_id serial PRIMARY KEY
, ... more columns
);
CREATE TABLE cat (
cat_id serial PRIMARY KEY
, cat text NOT NULL
);
CREATE TABLE search_cat (
search_id int REFERENCES search ON DELETE CASCADE
, cat_id int REFERENCES cat
, PRIMARY KEY (search_id, cat_id)
);
演示触发器的相关答案(不是针对唯一元素的唯一组合):