给定期望的结果和数据库信息,以编程方式构建一个提供这些结果的SQL查询

时间:2011-01-29 20:27:54

标签: sql algorithm

我认为没有一种简单的方法可以做到这一点,但是因为有机会......

我从1000万条记录表中获得了大约10000条记录的列表。数据当前由各种非索引元素的查询生成。我想使用十个单独的索引字段自动构建提供相同结果的查询。

有没有已知的算法来构建这样的东西?除了将每个索引“节点”包含在自己的OR中的基础之外,我的意思是。

例如,假设所需的数据是:

Letter, Number
A, 1
A, 2
B, 1
C, 2

并且原始数据库有

Letter, Number
A, 1
A, 2
A, 3
B, 1
C, 1
C, 2
D, 1
D, 3

我想要像:

WHERE ((Letter = 'A' OR Letter = 'B') AND (Number = 1 OR Number = 2)) 
OR (Letter = 'C' and Number = 2)

或者

WHERE (Letter IN ('A', 'B', 'C') AND Number IN (1, 2) 
AND NOT (Number = 1 AND Letter = 'C'))

但我认为我宁愿没有

WHERE (Letter = 'A' AND Number = '1') OR 
(Letter = 'A' AND Number = '2') OR
(Letter = 'B' AND Number = '1') OR
(Letter = 'C' AND Number = '2')

- 除非这里的数据库专家认为从长远来看会更加优化,对于我们所讨论的样本量。查询的运行时间很重要;转换工具的运行时间不是。我也不一定得到'最好'的答案; “足够好”是可以接受的。

我目前的计划是对可以组合在一起的事物进行计数,排序和迭代,以尽量减少“分组”;我想我宁愿没有一万(A和B和C和D和E和F和G和H和I和J)的ORed在一起。

思考?专家建议?

3 个答案:

答案 0 :(得分:1)

对不起,这不是你问题的答案,而是我自己对这个问题的思考。

我建议将您的列表存储在单独的表中。这将使您能够最终从两个表中进行连接选择。您可能会也可能不会在过滤器表上使用索引,具体取决于对数据的性能测试。

鉴于您打算使用的特定RDMBS,确切的实现会有所不同。在我的例子中,我会坚持使用Oracle,因为这是我最熟悉的。

CREATE TABLE t_filter_lists (
    f_letter varchar2(1),
    f_number number
);

-- Optionally, create an index:
CREATE INDEX ix_filter_lists
ON t_filter_lists (
    f_letter,
    f_number
);

INSERT INTO t_filter_lists (f_letter, f_number) VALUES ('A', 1);
INSERT INTO t_filter_lists (f_letter, f_number) VALUES ('A', 2);
INSERT INTO t_filter_lists (f_letter, f_number) VALUES ('B', 1);
INSERT INTO t_filter_lists (f_letter, f_number) VALUES ('C', 2);
COMMIT;

-- (Oracle-specific part) gather statistics on the filter table
EXEC DMBS_STATS.GATHER_TABLE_STATS(...

-- Run your query
SELECT *
FROM t_your_table t
    INNER JOIN t_filter_lists f
        ON  f.f_letter = t.t_letter
        AND f.f_number = t.t_number;

这个解决方案的好处是,鉴于表和索引统计信息是完整和新鲜的,根据列索引的列和方式,按顺序选择正确的谓词顺序,您将不会感到头疼。什么是他们的估计基数等优化器将为你做这项工作,它应该是非常好的。

答案 1 :(得分:0)

一种解决方案是在您不想要的场景中使用Except:

Select Letter, Number
From Table
Except
    (
    Select 'A', 3
    Union All 
    Select 'C', 1
    Union All 
    Select Distinct 'D', Number
    From Table
    )

另一种解决方案是简单地使用排除值列表填充临时表,并使用“除此之外”。

<强>加成

用于确定标准的算法的性质尚不清楚。是否要查找要包含或排除的项目?我最初的两个解决方案假设您正在构建一个排除列表。但是,如果要构建包含列表,那么显然您可以使用Intersect。此外,您可以使用值构造函数使列表更小:

Select Letter, Number
From Table
Intersect
Select *
From ( Values('A',1)
    , ('A',2), ('A',3), ('B',1), ('C',2) )

与Except方案一样,使用您想要的组合填充临时表并对其进行查询可能会更快。

答案 2 :(得分:0)

如果没有对问题的更多限制,这是不可能的。您可以使用几乎无限数量的过滤条件从数据库中选择一组行,并且根本无法对它们进行全部评估。例如,假设视图是由ID为prime的行构建的,或者是SHA1哈希以0结尾的行 - 您是否合理地期望任何自动过程能够发现这些规则?

此外,只给出匹配的行,就无法确定您构建的任何规则也不会从数据库中选择不匹配的其他记录 - 单独的正数集是不够的。