所谓的动态sql,就是在t-sql字符串内的sql,而静态sql就是直接写在t-sql 存储过程内的。动态sql的好处是可以写出非常复杂的,表达能力很强的sql,并且,因为某些条件下sql更简单,因此号称效率更好。而静态sql的好处在于可以调试,可以代码提示。不管怎样,我发现我们的sql很多都是动态的。尤其是在sqlserver缺乏分页支持的sql2000,很多需要分页的存储过程都是这样的。动态sql的强大能力来自于字符串的拼接,因此,如何改善字符串拼接就是对代码可读性进行优化的关键。如果能够改成静态sql而不必牺牲性能就更好了。
1. 加号拼接
这是最常见的拼接,特点是好写,缺点是难读。很多时候容易写的代码往往不容易阅读——因为不需要为变量取名字,完全就是具体数值的思维就可以。而需要参数化的sql语句,需要的是稍微抽象的参数化的思维。不过参数化的思维也不难,毕竟我们从初一就开始学习参数化的数学了。
Sql = "select top 1 typeid,sonnum,deleted from ptype where (usercode='" + pFullName + "' or fullname='" + pFullName + "') and typeid ='" + ptypeid + "'";
代码表示更加usercode,fullname,typeid的条件,列出 ptype表的第一行。这里面的“+”的引入,导致整个sql在阅读角度看起来是支离破碎,难以一目了然的了解代码的意图。其中的涉及到sql字符串定界符的“’”的处理也让人觉得很伤心。
尽管以c#代码为例,但是在t-sql内利用“+”来拼接也不在少数,表现的问题也差不多一样。
2. format拼接
还是以同样的代码为案例,以格式化函数的方式来看:
Sql = "select top 1 typeid,sonnum,deleted from ptype where (usercode='{0}'' or fullname='{0}') and typeid ='{1}'";
Sql=string.format(sql,fullname,typeid);
尽管增加了一个函数,但是sql显然变得比较完整,sql本身不完整的信息,以参数的方式提出来,“'”带来的阅读干扰也不像“加号拼接”那么碍眼。当然问题也是存在的:首先因为参数采用数字,因此当sql大些,参数多些的时候,找到参数对应关系会变得很麻烦。其次,依然存在sql injection(sql注入)的问题。
3. AddParameter拼接
还是以同样的代码为案例,以格式化函数的方式来看:
Sql = "select top 1 typeid,sonnum,deleted from ptype where (usercode=@fullname or fullname=@fullname) and typeid =@typeid";
db.AddParameter("@fullname", fullname);
db.AddParameter("@typeid",typeid);
我个人认为,这个方式的拼接sql方法是最好的。不但sql可以完整的阅读,参数还是有名称的——这样即使参数很多,sql很长,对阅读的额外障碍也不多。也不存在sql injection问题。至于"'"也无需考虑了。 但是需要为变参想名字,这是写起来要麻烦的一个原因吧。
这三种sql拼接的风格,都是以c#为例的,但是对存储过程也是一样的效果。仅仅是换门语言而已。
侧写:我看过的克服“‘”阅读干扰的方法:
采用 CHAR(10)来替代"'"
SET @strSQL=@strSQL+' LEFT JOIN SCM_BillType t ON a.BillType = t.BillType '+CHAR(10)
SET @strSQL=@strSQL+' LEFT JOIN Pub_DType d ON a.DID = d._ID '+CHAR(10)
这段代码还表明,作者希望通过left join前面加入很多空格来对齐,一边可以print来查看最后的sql是什么。看来,这个sql的作者写代码的时候也是希望看到完整的sql的。
改善sql字符串的可读性 - sql字符串常见编写风格