我想根据条件动态过滤数据,这些数据存储在特定的列中。此条件对于每一行都会改变。 例如,我有一个带有两列的表 my_table ,其中一列称为 foo ,其中有几个过滤条件,例如 AND bar > 1 或下一行 AND栏> 2 或下一行 AND栏= 33 。 我有一个查询,看起来像:
SELECT something from somewhere
LEFT JOIN otherthing on some_condition
WHERE first_condition AND second_condition AND
here_i_want_dynamically_load_condition_from_my_table.foo
正确的方法是什么?我已经阅读了一些有关动态查询的文章,但是找不到正确的方法。
答案 0 :(得分:0)
这在纯 SQL 中是不可能的:在查询时,规划器必须知道您的确切逻辑。现在,您可以将它隐藏在一个函数中(在伪 sql 中):
CREATE FUNCTION do_I_filter_or_not(some_id) RETURNS boolean AS '
BEGIN
value = select some_value from table where id = some_id
condition_type = SELECT ... --Query a condition type for this row
condition_value = SELECT ... --Query a condition value for this row
if condition_type = 'equals' and condition_value = value
return true
if condition_type = 'greater_than' and condition_value < value
return true
if condition_type = 'lower_than' and condition_value > value
return true
return false;
END;
'
LANGUAGE 'plpgsql';
然后像这样查询:
SELECT something
FROM somewhere
LEFT JOIN otherthing on some_condition
WHERE first_condition
AND second_condition
AND do_I_filter_or_not(somewhere.id)
现在性能会很差:您必须在查询的每一行上潜在地调用该函数;触发大量子查询。
考虑一下,如果您只想要 <、>、=,并且您有一个表 (filter_criteria) 描述每个 id 的标准是什么,您可以这样做:
CREATE TABLE filter_criteria AS(
some_id integer,
equals_threshold integer,
greater_than_threshold integer,
lower_than_threshold integer
-- plus a check that two thresholds must be null, and one not null
)
INSERT INTO filter_criteria (1, null, 5, null); -- for > 5
然后像这样查询:
SELECT something
FROM somewhere
LEFT JOIN otherthing on some_condition
LEFT JOIN filter_criteria USING (some_id)
WHERE first_condition
AND second_condition
AND COALESCE(bar = equals_threshold, true)
AND COALESCE(bar > greater_than_threshold, true)
AND COALESCE(bar < lower_than_threshold, true)
如果阈值缺失,COALESCE
在这里默认为不过滤 (AND true
)(bar = equals_threshold 将产生 null 而不是布尔值)。
规划器必须在查询时知道您的确切逻辑:现在您只需进行 3 次过滤,每次都使用 =、<、> 检查。对于所有子查询,这仍然比想法 #1 的性能更高。