我负责许多存储过程,它们的形式如下:
create procedure getFoos()
begin
set @v_sql := '';
set @v_sql := concat(@v_sql, 'select distinct ', getFooFields('f', 'b'), ' ');
set @v_sql := concat(@v_sql, 'from Foos f ');
set @v_sql := concat(@v_sql, ' left join Bars b on f.barID= b.barID');
set @v_sql := concat(@v_sql, 'where f.someDate is null ');
set @v_sql := concat(@v_sql, ' and b.someID in (1, 2, 3) ');
set @v_sql := concat(@v_sql, ' and b.someBool = true ');
set @v_sql := concat(@v_sql, 'order by f.name ');
prepare s1 from @v_sql;
execute s1;
deallocate prepare s1;
end;
正如您所看到的,使用动态SQL可以内联函数getFooFields
。该函数仅用于建立选定字段的字符串:
create function getFooFields(
i_aliasForFoo varchar(32),
i_aliasForBar varchar(32)
) returns text
reads sql data
begin
declare v_fields text default '';
set v_fields := concat(v_fields, i_aliasForFoo, '.fooID as fooId', ', ');
set v_fields := concat(v_fields, i_aliasForFoo, '.someDate as someDate ', ', ');
set v_fields := concat(v_fields, i_aliasForFoo, '.name as name', ', ');
-- additional Foo fields
set v_fields := concat(v_fields, i_aliasForBar, '.someID as someID ', ', ');
set v_fields := concat(v_fields, i_aliasForBar, '.someBool as someBool ', ', ');
-- additional Bar fields
return v_fields;
end;
这样做的原因似乎是更好的可维护性——当更改Foos
或Bars
表时,只需在一个函数中进行更改,而不需要在多个过程中进行更改。然而,这是以使用动态SQL以及一个额外的函数为代价的,该函数每次调用时都会构建相同的字符串。我想知道是否有一种方法可以在将工作转移到运行前的同时保持可维护性。
碰巧的是,我们在Eclipse中管理SQL,并在每次部署之前在数据库上运行这些文件之前使用Ant对这些文件进行处理。有没有一种方法可以让Ant编写脚本来代替getFooFields
的工作?我想象如下:
select distinct <%foofields%> from Foos
...
其中Ant将用类似于getFooFields
正在构建的字符串替换<%foofields%>
。当然,由于getFooFields
需要参数,这一点更加复杂,所以我不确定这将如何工作。
这个想法完全被误导了吗?我对蚂蚁几乎没有任何经验,所以我说不出来。或者,在保持这些过程的可维护性的同时,还有什么其他方法可以消除这些过程对动态SQL的依赖?
如果getFooFields
最常用于从表foo
中选择所有字段,那么使用select * from foo
比使用动态SQL和函数的组合更好。
如果它是foo
中经常作为一个组出现的字段的子集,那么将该子集创建为视图并针对该视图进行查询可能会更好。
如果getFooFields
从另一个应用程序中获取字段列表以从foo
中进行选择,那么您必须检查这是否有意义。foo
中有多少字段?您多长时间只需要这些字段中的一小部分?您是否提取了足够多的记录以使这种类型的"优化"具有意义?最有可能的是,你不是,而且最好只是把公共领域或所有领域都拉出来。