这就是我的做法。
第一:权重
由于您说权重会不时变化,因此您必须创建一个结构来处理这些变化。它可以是一个简单的表。对于这个解决方案,它将被称为权重。
-- Table: weights
CREATE TABLE weights(id serial, table_nane text, column_name text, weight numeric(5,2));
id | table_name | column_name | weight
---+------------+--------------+--------
1 | resources | name | 40.00
2 | resources | provider | 30.00
3 | resources | description | 20.00
4 | resources | category | 10.00
因此,当您需要将类别从 10 更改为 20 或/和描述从 20 更改为 10 时,您需要更新此结构。
第二个:completion_level
既然你说你可以有几百万行,那么在表resources中有completion_level列是可以的;出于效率目的。
查询completion_level 工作,您可以在视图中看到它。但是当您需要快速简单的数据并且您有 MILLIONS 行时,最好将数据设置为“default”列或另一个表中。
当您拥有一个视图时,每次运行它时,它都会重新创建数据。当你已经把它放在桌子上时,它很快,你不必重新创建任何东西,只需查询数据。
但是如何处理完成级别? TRIGGERS
您必须为resources 表创建触发器。因此,每当您更新或插入数据时,它都会创建完成级别。
首先将列添加到resources 表中
ALTER TABLE resources ADD COLUMN completion_level numeric(5,2);
然后你创建触发器:
CREATE OR REPLACE FUNCTION update_completion_level() RETURNS trigger AS $$
BEGIN
NEW.completion_level := (
CASE WHEN NEW.name IS NULL THEN 0
ELSE (SELECT weight FROM weights WHERE column_name='name') END
+ CASE WHEN NEW.provider IS NULL THEN 0
ELSE (SELECT weight FROM weights WHERE column_name='provider') END
+ CASE WHEN NEW.description IS NULL THEN 0
ELSE (SELECT weight FROM weights WHERE column_name='description') END
+ CASE WHEN NEW.category IS NULL THEN 0
ELSE (SELECT weight FROM weights WHERE column_name='category') END
);
RETURN NEW;
END $$ LANGUAGE plpgsql;
CREATE TRIGGER resources_completion_level
BEFORE INSERT OR UPDATE
ON resources
FOR EACH ROW
EXECUTE PROCEDURE update_completion_level();
注意:表weights 有一个名为table_name 的列;以防万一您想将此功能扩展到其他表。在这种情况下,您应该更新触发器并在查询中添加 AND table_name='resources'。
使用此触发器,每次更新或插入时,您都会准备好 completion_level,因此获取此数据将是对 resources 表的简单查询;)
第三:旧数据和权重更新呢?
由于触发器仅适用于更新和插入,那么旧数据呢?或者如果我更改列的权重会怎样?
好吧,对于这些情况,您可以使用 函数 为每一行重新创建所有 completion_level。
CREATE OR REPLACE FUNCTION update_resources_completion_level() RETURNS void AS $$
BEGIN
UPDATE resources set completion_level = (
CASE WHEN name IS NULL THEN 0
ELSE (SELECT weight FROM weights WHERE column_name='name') END
+ CASE WHEN provider IS NULL THEN 0
ELSE (SELECT weight FROM weights WHERE column_name='provider') END
+ CASE WHEN description IS NULL THEN 0
ELSE (SELECT weight FROM weights WHERE column_name='description') END
+ CASE WHEN category IS NULL THEN 0
ELSE (SELECT weight FROM weights WHERE column_name='category') END
);
END $$ LANGUAGE plpgsql;
所以每次更新权重或更新旧数据时,只需运行函数
SELECT update_resources_completion_level();
最后:如果我添加列会怎样?
好吧,您必须在weights 表中插入新列并更新函数(触发器和update_resources_completion_level())。设置好所有内容后,运行函数update_resources_completion_level() 以根据更改设置所有权重:D