SQL Case语句,在条件上进行子选择?

时间:2012-09-28 08:59:18

标签: sql-server tsql case

我遇到过一种情况,我需要在从“遗留”到当前的交叉点返回一组复杂的计算值。

总而言之,我有类似的东西......

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

2 个答案:

答案 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()部分

中处理