我正在运行一个SQL查询,它自动加入同一个表24次,以便查找"查找"根据24个不同的标准,表的特定行,以便我可以在计算中使用所有这些值。虽然表现非常好(表格被编入索引,加入标准也是限制性的),但我无法帮助,但感觉这里有代码味道。
有没有更好的方法在SQL中进行查找?
(道歉不包括一个例子;我希望我以一般方式表达了这个问题。)
编辑:无论如何尝试一个例子:
CREATE TABLE key (
pk1 int,
pk2 int,
pk3 int,
PRIMARY KEY (pk1, pk2, pk3)
);
CREATE TABLE values (
pk1 int,
pk2 int,
pk3 int,
pk4 int,
pk5 int,
value int,
PRIMARY KEY (pk1, pk2, pk3, pk4, pk5)
);
SELECT k.pk1, k.pk2, k.pk3,
v1.value + v2.value - v3.value * (v4.value / v5.value) + ... + v24.value as result
FROM key k
LEFT JOIN values v1
on v1.pk1=k.pk1
and v1.pk2=k.pk2
and v1.pk3=k.pk3
and v1.pk4=100
and v1.pk5=200
LEFT JOIN values v2
on v2.pk1=k.pk1
and v2.pk2=k.pk2
and v2.pk3=k.pk3
and v2.pk4=400
and v2.pk5=800
...
LEFT JOIN values v24
on v24.pk1=k.pk1
and v24.pk2=k.pk2
and v24.pk3=k.pk3
and v24.pk4=900
and v24.pk5=700;
编辑2:这种结构的原因是值表表示(数学上说)5个变量的函数,预先计算的返回值存储在表中,用于各种参数。
答案 0 :(得分:2)
首先,这不是一个自我加入。
自联接是表连接到自身的时候。
这方面的例子是层次结构中的父子关系以及与其他人(字面意思是父母,孩子)有关系的人。
您使用不同角色的表格的情况并不罕见。
如果表中的不同值在某种基本性质上没有关系,我会将设计问题作为“一次真正查找”的情况,其中一个存储各种类型的实体查找代码 - 因此您可以在同一个查找表中获取帐单地址,客户,送货地址,产品和各种各样的东西。
在数据仓库中,也可以使用不同角色的维度,特别是日期或时间维度。
如果对于用作数组的列反复连接相同的查找表,就会产生异味 - 例如first_child,second-child,third_child - 因为这通常违反了规范化。
我对你在这里展示的内容的唯一顾虑是:
似乎用于在所有值的5维空间中拾取三维空间的幻数。我假设这些本身是在某个表格中定义的(pk4,pk5,description)。
此时我会考虑将每个视图转换为视图以使其更具可读性。
在SQL Server(或具有相同构造的DB2)中,我实际上会考虑使用在pk4和pk5上参数化的内联表值函数,这有助于防止某人意外加入不完整的连接标准 - 以及以一个ITVF而不是许多观点结束。
但所有这些只是清理 - 查询和表格的设计对我来说似乎很合理。
答案 1 :(得分:1)
我已经开始用整个查找表示例回答这个问题,但意识到存在更大的潜在问题。
查看这些参考文献。
http://en.wikipedia.org/wiki/Entity-attribute-value_model
Key value pairs in relational database
您正在使用的架构类型与关系数据库的概念相反。尝试展平您的表格,以便您没有键/值关系。
如果你的等式是一个非正则的聚合(是的,不要查找那个),例如v1.val + v2.val / v3.val,那么你想要在该等式中得到每个变量在一个或多个(但少于24个)连接之后,在一个或多个表中的单行中。
实体 - 属性 - 值模式遭受性能差,维护困难以及真正非常难闻的气味。
...
这没有回答这个问题,所以这里有。使用像Icarus在评论中建议的视图,或者将整个事情烧掉并重建一些更加规范化的东西。
答案 2 :(得分:1)
看到您正在使用SAS,您可以使用数据步骤合并来清理它。有点像:
data x;
merge key
values(rename=value=value1 where=(pk4=100 and pk5=200))
values(rename=value=value2 where=(pk4=400 and pk5=800))
values(rename=value=value3 where=(pk4=900 and pk5=700))
etc...
;
by pk1 pk2 pk3;
result = ...;
keep pk: value: result;
run;
我现在面前没有SAS,所以我不打算输入所有代码并测试它,但是你明白了。对我来说,我认为它看起来比SQL更清洁。当datastep merge提供比SQL方法更好的替代方案时,这是一个非常罕见的发现。
答案 3 :(得分:0)
如果我理解你正在寻找的东西,它更容易使用:
SELECT field1, field2 from Table1 t
where exists (SELECT 1 from LookupTable l where l.fieldX=t.fieldX)
答案 4 :(得分:0)
我列举了pk4,pk5的参数对为num(我将实际数字替换为4 * 6):
CREATE TABLE zparams
( num INTEGER
, pk4 INTEGER
, pk5 INTEGER
, PRIMARY KEY (pk4,pk5)
, CONSTRAINT ze_other UNIQUE (num)
);
INSERT INTO zparams(num,pk4,pk5) VALUES
(1,1,1), (2,1,2), (3,1,3), (4,1,4), (5,1,5), (6,1,6)
, (7,2,1), (8,2,2), (9,2,3), (10,2,4), (11,2,5), (12,2,6)
, (13,3,1), (14,3,2), (15,3,3), (16,3,4), (17,3,5), (18,3,6)
, (19,4,1), (20,4,2), (21,4,3), (22,4,4), (23,4,5), (24,4,6)
;
CTE的收益相当无效:
EXPLAIN ANALYZE
WITH zzz AS (
SELECT v.pk1 AS pk1
, v.pk2 AS pk2
, v.pk3 AS pk3
, p.num AS num
, v.value AS value
FROM zparams p
JOIN zvalues v ON v.pk4 = p.pk4 AND v.pk5=p.pk5
)
SELECT k.pk1, k.pk2, k.pk3,
v1.value + v2.value - v3.value * (v4.value / v5.value) + v24.value as result
FROM zkeys k
LEFT JOIN zzz v1
ON v1.pk1=k.pk1 AND v1.pk2=k.pk2 AND v1.pk3=k.pk3
AND v1.num=1
LEFT JOIN zzz v2
ON v2.pk1=k.pk1 AND v2.pk2=k.pk2 AND v2.pk3=k.pk3
AND v2.num=2
LEFT JOIN zzz v3 ON v3.pk1=k.pk1 AND v3.pk2=k.pk2 AND v3.pk3=k.pk3
AND v3.num=3
LEFT JOIN zzz v4
ON v4.pk1=k.pk1 AND v4.pk2=k.pk2 AND v4.pk3=k.pk3
AND v4.num=4
LEFT JOIN zzz v5
ON v5.pk1=k.pk1 AND v5.pk2=k.pk2 AND v5.pk3=k.pk3
AND v5.num=5
LEFT JOIN zzz v24
ON v24.pk1=k.pk1 AND v24.pk2=k.pk2 AND v24.pk3=k.pk3
AND v24.num=24
;
并且,在100K * 24变量(6used)上测试,实际上 - CTE比{pk1,pk2,pk3,pk4 =常数,pk5 =常数}上的普通连接(1秒)表现更差(4.5秒)。但是,至少它看起来更干净。
答案 5 :(得分:0)
作为上述答案的替代方案,你也可以做一些我相信的事情:
CREATE TABLE XX AS
SELECT k.pk1, k.pk2, k.pk3, v1.pk4, v1.pk5, v1.value
FROM key k
LEFT JOIN values v1
on v1.pk1=k.pk1
and v1.pk2=k.pk2
and v1.pk3=k.pk3
and (
(v1.pk4=100 and v1.pk5=200) or
(v1.pk4=400 and v1.pk5=800) or
(v1.pk4=700 and v1.pk5=900)
)
proc transpose data=xx out=trans;
by pk1 pk2 pk3;
var value;
run;
data result;
set trans;
result = ...;
run;
同样,我没有在我面前的SAS,所以我无法测试它,但我相信你能得到它。这样,您只需要进行一次连接,然后将其余部分分解为其他步骤。我不太确定这将如何执行,因为它可能不再使用索引。只是抛出一些想法......