这可能不是一个直截了当的Firebird问题,但我希望有一个我不知道的功能可以帮助我超越普通的SQL。
我有两张桌子。第一个是“关键参数”的名称列表,第二个是关联某些对象ID,关键参数名称和关键参数值:
CREATE TABLE CRITICALPARAMS
(
PARAM Varchar(32) NOT NULL,
INDX INTEGER NOT NULL,
CONSTRAINT PK_CRITICALPARAMS_1 PRIMARY KEY (PARAM),
CONSTRAINT UNQ_CRITICALPARAMS_1 UNIQUE (INDX)
);
CREATE TABLE CRITICALPARAMVALS
(
ID INTEGER NOT NULL,
PARAM Varchar(32) NOT NULL,
VAL Float NOT NULL,
CONSTRAINT PK_CRITICALPARAMVALS_1 PRIMARY KEY (ID,PARAM)
);
让我们假设我们有一个四维空间:
insert into CRITICALPARAMS values ('a', 1);
insert into CRITICALPARAMS values ('b', 2);
insert into CRITICALPARAMS values ('c', 3);
insert into CRITICALPARAMS values ('foo', 4);
......以及那个空间中的一些物品:
insert into CRITICALPARAMVALS values (1, 'a', 0.0);
insert into CRITICALPARAMVALS values (1, 'b', 0.0);
insert into CRITICALPARAMVALS values (1, 'c', 2.0);
insert into CRITICALPARAMVALS values (1, 'foo', 99.0);
insert into CRITICALPARAMVALS values (2, 'a', 0.0);
insert into CRITICALPARAMVALS values (2, 'b', 0.0);
insert into CRITICALPARAMVALS values (2, 'c', 2.0);
insert into CRITICALPARAMVALS values (2, 'foo', 99.0);
insert into CRITICALPARAMVALS values (3, 'a', 0.0);
insert into CRITICALPARAMVALS values (3, 'b', 0.0);
insert into CRITICALPARAMVALS values (3, 'c', 1.0);
insert into CRITICALPARAMVALS values (3, 'foo', 98.0);
insert into CRITICALPARAMVALS values (4, 'a', 0.0);
insert into CRITICALPARAMVALS values (4, 'b', 0.0);
insert into CRITICALPARAMVALS values (4, 'c', 1.0);
insert into CRITICALPARAMVALS values (4, 'foo', 98.0);
insert into CRITICALPARAMVALS values (5, 'a', 0.0);
insert into CRITICALPARAMVALS values (5, 'b', 0.0);
insert into CRITICALPARAMVALS values (5, 'c', 2.0);
insert into CRITICALPARAMVALS values (5, 'foo', 98.0);
问题是对关键参数空间进行分区,将具有相同参数值的所有对象ID分组在一起。我们可以考虑使用“种子”对象ID,并询问其他ID与种子对象属于同一分区。
在我们的例子中,对象1和2形成一个分区,3和4形成另一个,5形成第三个。关键参数a和b中的所有五个对象相等,但参数c和foo不同。
有没有办法用普通的SQL来解决这个问题?如何递归CTE?
我已经粗略地解决了这个问题,在存储过程中使用EXECUTE STATEMENT,循环遍历种子的关键参数值,并手动构建一个包含尽可能多WHERE子句作为关键参数的大型SQL语句,但该解决方案不能扩展为我上升到大约500-1000个关键参数(或更多!)。
我目前的尝试已经逐渐消失了 - 我首先定义一个视图,它可以给我一个关键参数的分区(TEST_FLOAT_EQ是一个可选择的存储过程,比较两个浮点数'足够好!'相等) :
CREATE VIEW VGROUPIDBYPARAM (SEEDID, GROUPMEMBERID, CRITPARAMINDX)
AS
select a.id as seedid, b.id as groupmemberid, c.INDX as critparamindx
from CRITICALPARAMVALS a
join CRITICALPARAMVALS b on a.PARAM=b.param and (exists (select isequal from TEST_FLOAT_EQ(a.val, b.val, 1e-5) where ISEQUAL=1))
join CRITICALPARAMS c on b.param=c.PARAM;
...然后我想归纳地使用VGROUPIDBYPARAM视图,类似于以下部分完整的选择:
SELECT a1.SEEDID, a6.GROUPMEMBERID
FROM VGROUPIDBYPARAM a1
join VGROUPIDBYPARAM a2 on a1.SEEDID=a2.SEEDID and a1.GROUPMEMBERID=a2.GROUPMEMBERID
join VGROUPIDBYPARAM a3 on a1.SEEDID=a3.SEEDID and a2.GROUPMEMBERID=a3.GROUPMEMBERID
join VGROUPIDBYPARAM a4 on a1.SEEDID=a4.SEEDID and a3.GROUPMEMBERID=a4.GROUPMEMBERID
join VGROUPIDBYPARAM a5 on a1.SEEDID=a5.SEEDID and a4.GROUPMEMBERID=a5.GROUPMEMBERID
join VGROUPIDBYPARAM a6 on a1.SEEDID=a6.SEEDID and a5.GROUPMEMBERID=a6.GROUPMEMBERID
...
where a1.CRITPARAMINDX=1
and a2.CRITPARAMINDX=2
and a3.CRITPARAMINDX=3
and a4.CRITPARAMINDX=4
and a5.CRITPARAMINDX=5
and a6.CRITPARAMINDX=6
...
在这个归纳过程结束时(我希望递归CTE可以模仿),唯一幸存的记录通过一堆JOINS使组成员ID属于与种子ID相同的分区。 / p>
非常感谢能够帮助我有效解决问题的任何人!
答案 0 :(得分:2)
要解决这个问题,我会从这个简单的查询开始(计算其他对象中的匹配维度):
SELECT
CPV1.ID AS ID1,
CPV2.ID AS ID2,
COUNT(*)
FROM
CRITICALPARAMVALS CPV1
INNER JOIN CRITICALPARAMVALS CPV2 ON CPV1.ID <> CPV2.ID
AND CPV1.PARAM = CPV2.PARAM
AND CPV1.VAL = CPV2.VAL
GROUP BY
CPV1.ID, CPV2.ID
使用以下输出:
如您所见,有趣的行标有黄色背景。
要仅过滤那些行,我们应该添加以下条件:
HAVING COUNT(*) = (SELECT COUNT(*) FROM CRITICALPARAMS)
我们可以考虑使用&#34;种子&#34;对象ID,并询问其他ID 属于与种子对象相同的分区。
使用:SEED
参数回答上述问题的最终查询如下所示:
SELECT
CPV2.ID
FROM
CRITICALPARAMVALS CPV1
INNER JOIN CRITICALPARAMVALS CPV2 ON CPV1.ID <> CPV2.ID
AND CPV1.PARAM = CPV2.PARAM
AND CPV1.VAL = CPV2.VAL
WHERE CPV1.ID = :SEED
GROUP BY
CPV1.ID, CPV2.ID
HAVING COUNT(*) = (SELECT COUNT(*) FROM CRITICALPARAMS)
即使对于大数据集也应该表现良好。