我遇到过一种情况,我需要在从“遗留”到当前的交叉点返回一组复杂的计算值。
总而言之,我有类似的东西......
with someofit as
(
select id, col1, col2, col3 from table1
)
select someofit.*,
case when id < @lastLegacyId then
(select ... from table2 where something = id) as 'bla'
,(select ... from table2 where something = id) as 'foo'
,(select ... from table2 where something = id) as 'bar'
else
(select ... from table3 where something = id) as 'bla'
,(select ... from table3 where something = id) as 'foo'
,(select ... from table3 where something = id) as 'bar'
end
from someofit
这不是问题所在...... 我不想经常对每个子选择进行该情况检查,但同时当该条件适用时,我需要相关案例块中的所有选择。
有更聪明的方法吗?
如果我使用适当的OO语言,我会使用类似的东西......
var common = GetCommonSuff()
foreach (object item in common)
{
if(item.id <= lastLegacyId)
{
AppendLegacyValuesTo(item);
}
else
{
AppendCurrentValuesTo(item);
}
}
我最初尝试使用union进行2次完整选择,但由于要评估的效率/行数,这不能很好地工作。
子选择正在寻找除了表2或表3上的id匹配之外满足某些条件的总行数,但这些表中可能有数百万行。
使用cte有两个原因......
首先它只从表1中拉出我感兴趣的行,所以我只是在每种情况下只做一小部分子选择。
其次,它在表1的单个查找中返回常见内容
有什么想法吗?
编辑1:
情况的一些背景......
我有一个名为“imports”的表(上面的表1),这表示一个导入作业,我们从文件(csv或类似文件)中获取数据并将记录拉入db。
然后我有一个名为“steps”的表,它表示我们经历的处理/清理规则,每个记录包含一个sproc名称和一堆关于规则的其他内容。
然后有一个连接表,表示特定导入“ImportSteps”的规则(上面的表2 - 对于当前数据),其中包含“rowsaffected”列和导入ID
所以对于当前的工作,我的sql很简单......
选择123 456 来自进口 加入importsteps
对于较旧的遗留物,但是我必须查看表3 ...表3是保持表,它包含导入的每个记录,每行都有一个导入ID,每行包含键值。
对于导入ID为表2的新数据行,其中步骤id为y将返回我的值。
关于遗留数据我必须计算保持行的行,其中col z = something
我需要大约20个导入的数据,这个数据绑定到我的mvc web应用程序上的“datagrid”(如果这有任何区别)
我使用的cte通过一些参数确定“当前20我感兴趣的”那些参数表示开始和结束记录(按导入ID排序)。
我最大的问题是拿着桌子...它很大..已知个别作业自己包含500k +记录,而且这个表保存了多年的导入行,所以我需要在该表上查找速度一样快尽可能少。
编辑2:
实际解决方案(仅限suedo代码)......
-- declare and populate the subset to reduce reads on the big holding table
declare table @holding ( ... )
insert into @holding
select .. from holding
select
... common stuff from inner select in "from" below
... bunch of ...
case when id < @legacy then (select getNewValue(id, stepid))
else (select x from @holding where id = ID and ... ) end as 'bla'
from
(
select ROW_NUMBER() over (order by importid desc) as 'RowNum'
, ...
) as I
-- this bit handles the paging
where RowNum >= @StartIndex
and RowNum < @EndIndex
我仍然有信心我可以清理它,但我的原始查询看起来像票据解决方案执行时间约为45秒,这是大约7
答案 0 :(得分:3)
我认为子查询必须返回单个标量值,对吗?这一点很重要,因为它确保LEFT JOIN不会使结果倍增。
;with someofit as
(
select id, col1, col2, col3 from table1
)
select someofit.*,
bla = coalesce(t2.col1, t3.col1),
foo = coalesce(t2.col2, t3.col2),
bar = coalesce(t2.bar, t3.bar)
from someofit
left join table2 t2 on t2.something=someofit.id and somefit.id < @lastLegacyId
left join table3 t3 on t3.something=someofit.id and somefit.id >= @lastLegacyId
请注意我已使用id >= @lastLegacyId
作为条件的补充,假设id不可为空。如果是,那么你需要一个IsNull,即somefit.id >= isnull(@lastLegacyId,somefit.id)
。
您对该问题的编辑并未改变这一事实,即这是O-O语法的几乎字面翻译。
foreach (object item in common) --> "from someofit"
{
if(item.id <= lastLegacyId) --> the precondition to the t2 join
{
AppendLegacyValuesTo(item); --> putting t2.x as first argument of coalesce
}
else --> sql would normally join to both tables
--> hence we need an explicit complement
--> condition as an "else" clause
{
AppendCurrentValuesTo(item); --> putting t3.x as 2nd argument
--> tbh, the order doesn't matter since t2/t3
--> are mutually exclusive
}
}
function AppendCurrentValuesTo --> the correlation between t2/t3 to someofit.id
现在,如果你真的尝试了这个并且它没有解决你的问题,我想知道它在哪里崩溃。
答案 1 :(得分:1)
假设您知道两个表之间没有冲突的ID,您可以执行类似这样的操作(DB2语法,因为这是我所知道的,但它应该类似):
with combined_tables as (
select ... as id, ... as bla, ...as bar, ... as foo from table 2
union all
select ... as id, ... as bla, ...as bar, ... as foo from table 3
)
select someofit.*, combined_ids.bla, combined_ids.foo, combined_ids.bar
from someofit
join combined_tables on someofit.id = combined_tables.id
如果您遇到重叠ID等情况,可以在combined_tables()部分
中处理