`

一些注意的sql写法

 
阅读更多
  Dashboard > 流程空间 > home > SQLMAP编写规范以及一些常见的SQL问题     
Page Operations
View Edit Attachments (0) Info
Browse Space
Pages Labels Attachments Mail News Templates Advanced
Add Content
Add Page  Add News  Welcome 李文学 | History | Preferences | Log Out    
  流程空间
SQLMAP编写规范以及一些常见的SQL问题
Added by 李文学, last edited by 李文学 on 五月 18, 2007  (view change) Labels: (None) EDIT

Add Labels  
Enter labels to add to this page:
  Tip: Looking for a label? Just start typing.  



select语句中*号的问题
1。表连接时,绝不允许写select * ,否则按照编码错误Bug处理。

2。单表查询,一般情况下可以使用select * ,但以下几种情况禁用:
   a、表中包含lob字段(BLOB、CLOB、LONG、LONG RAW等)。
   b、表中包含长度较大的字段,如varchar2(1000)以上的字段,但该SQL实际上并不需要取出该字段的值。
   c、字段数量很多,但实际要用的字段很少,比如表有50个字段,而你实际只用5个,并且该sql目前没有被重用。
   d、DBA要求优化调整的。

严格要求使用正确类型的变量,杜绝oracle做隐式类型转换的情况
1。推荐在sqlmap的变量中指定变量的数据类型,如:

select * from iw_user where iw_user_id = #userid:VARCHAR#2。其中,对于时间类型的字段,必须使用TO_DATE进行赋值(当前时间可直接用sysdate表示),不允许下列这些错误用法:

   错误的写法(使用date类型的变量):

select * from iw_account_log where trans_account = #transaccount:varchar#
   and trans_dt >= #dateBegin:date#
   and trans_dt < #dateEnd:date#   错误的写法(使用包含sysdate的表达式):

select * from iw_account_log where trans_account = #transaccount:varchar#
   and trans_dt >= trunc(sysdate - 1)
   and trans_dt < sysdate + 1   错误的写法(将to_date函数和数字进行算术运算):

select * from iw_account_log where trans_account = #transaccount:varchar#
   and trans_dt >= to_date(#dateBegin:varchar#, 'yyyy-mm-dd hh24:mi:ss')
   and trans_dt < to_date(#dateBegin:varchar#, 'yyyy-mm-dd hh24:mi:ss') + 1   正确的写法:

select * from iw_account_log where trans_account = #transaccount:varchar#
   and trans_dt >= to_date(#dateBegin:varchar#, 'yyyy-mm-dd hh24:mi:ss')
   and trans_dt < to_date(#dateEnd:varchar#, 'yyyy-mm-dd hh24:mi:ss')       /*或 trans_dt < sysdate */3。对于变量数据类型错误导致SQL严重性能问题的,按严重的编码错误Bug处理!

杜绝循环调用
   例如:在迭代的过程中,使用同一SQL反复查询DB,如:

while (listObj.hasnext()) {
  SELECT * FROM beyond_trade_process WHERE (trade_no = ?)
  ......
}   这样不仅效率不高,还造成交互过于频繁,严重情况会导致服务器LOAD增加
   解决方式:
   1。如果该查询是使用唯一键(如上例),参考后面的STR2VARLIST或STR2NUMLIST的用法
   2。联系DBA协助分析解决方式
   3。违反本条规范,属较严重Bug,如是前台应用应立即予以修复

绑定变量和替代变量
在Ibatis中:
绑定变量用 #变量名# 表示
替代变量用 $变量名$ 表示

注意几点:
1。通常,应使用绑定变量,尤其是具体取值变化范围较大的变量,如iw_user_id = #userid#。
2。取值范围很小(比如枚举字段),并且通常取值会比较固定,在DBA预先同意的情况下使用替代变量,或者干脆使用常量。
3。当一个绑定变量在实际使用中实际取值总是为某一固定常量时,应当直接使用常量而不是变量,关于这点,可在具体使用时咨询DBA
4。在order by子句中,通常使用替代变量而不是绑定变量。
5。IN子句,使用"iterate + 数组类型变量"的方式实现绑定变量,例如:

<isNotEmpty prepend="and" property="userIds">
     <iterate  property="userIds" open="t.creator in (" close=")" conjunction=",">
          #userIds[]#
     </iterate>
</isNotEmpty>将生成 t.creator in (:1, :2, :3, :4, :5 ...) 的语句

在字段上加函数的问题
1。通常,不允许在字段上添加函数或者表达式,如:

   错误的写法:

select * from iw_account_log where to_char ( trans_dt, 'yyyy-mm-dd') = '2007-04-04';
select qty from product where p_id + 12 = 168;   正确的写法:

select * from iw_account_log
   where trans_dt >= to_date ( '2007-04-04', 'yyyy-mm-dd') and trans_dt < to_date ( '2007-04-05', 'yyyy-mm-dd');
select qty from product where p_id = 168 - 12;2。如果是业务要求的除外,但需要在编写时咨询DBA

3。特别注意,当表连接时,用于连接的两个表的字段如果数据类型不一致,则必须在一边加上类型转换的函数,如

   错误的写法(a.id是number类型,而b.operator_number是char类型):

select count(*) from adm_user a, adm_action_log b where a.id = b.operator_number and a.username = '小钗';   正确的写法:

select count(*) from adm_user a, adm_action_log b where to_char(a.id) = b.operator_number and a.username = '小钗';
select count(*) from adm_user a, adm_action_log b where a.id = to_number(b.operator_number) and a.username = '小钗';   上面两种写法哪个正确?遇到这种情况时必须咨询DBA!

表连接
1。不使用ANSI连接,如inner join、left join、right join、full outer join,而使用(+)来表示外连接

   错误的写法:

select a.*, b.goods_title from iw_account_log a left join beyond_trade_base b on a.TRANS_OUT_ORDER_NO = b.trade_no
   where a.trans_code = '6003' and a.trans_account = #transacnt:varchar# and a.trans_dt > to_date(...)   正确的写法:

select a.*, b.goods_title from iw_account_log a, beyond_trade_base b
   where a.TRANS_OUT_ORDER_NO = b.trade_no(+) and a.trans_code = '6003'
   and a.trans_account = #transacnt:varchar# and a.trans_dt > to_date(...)SQLMAP的其它编写规范
1。对表的记录进行更新的时候,必须包含对gmt_modified字段的更新,并且不要使用dynamic标记,如:

   错误的写法:

update BD_CONTACTINFO
       <dynamic prepend="set">
           ......
           <isNotNull prepend="," property="gmtModified">
               GMT_MODIFIED = #gmtModified:TIMESTAMP#
           </isNotNull>
       </dynamic>
   where ID = #id#   正确的写法(当然,这里更推荐直接更新为sysdate):

update BD_CONTACTINFO
       set GMT_MODIFIED = #gmtModified:TIMESTAMP#
       <dynamic>
           ......
       </dynamic>
   where ID = #id#2。不允许在where后添加1=1这样的无用条件,where可以写在prepend属性里,如:

   错误的写法:

select count(*) from BD_CONTRACT t where 1=1
       <dynamic>
           ......
       </dynamic>   正确的写法:

select count(*) from BD_CONTRACT t
       <dynamic prepend="where">
           ......
       </dynamic>3。对大表进行查询时,在SQLMAP中需要加上对空条件的判断语句,具体可在遇到时咨询DBA,如:

   性能上不保险的写法:

select count(*) from iw_user usr
   <dynamic prepend="where">
       <isNotEmpty prepend="AND" property="userId">
           usr.iw_user_id = #userId:varchar#
       </isNotEmpty>
       <isNotEmpty prepend="AND" property="email">
           usr.email = #email:varchar#
       </isNotEmpty>
       <isNotEmpty prepend="AND" property="certType">
           usr.cert_type = #certType:varchar#
       </isNotEmpty>
       <isNotEmpty prepend="AND" property="certNo">
           usr.cert_no = #certNo:varchar#
       </isNotEmpty>
   </dynamic>   性能上较保险的写法(防止那些能保证查询性能的关键条件都为空):

select count(*) from iw_user usr
   <dynamic prepend="where">
       <isNotEmpty prepend="AND" property="userId">
           usr.iw_user_id = #userId:varchar#
       </isNotEmpty>
       <isNotEmpty prepend="AND" property="email">
           usr.email = #email:varchar#
       </isNotEmpty>
       <isNotEmpty prepend="AND" property="certType">
           usr.cert_type = #certType:varchar#
       </isNotEmpty>
       <isNotEmpty prepend="AND" property="certNo">
           usr.cert_no = #certNo:varchar#
       </isNotEmpty>
       <isEmpty property="userId">
            <isEmpty property="email">
                <isEmpty property="certNo">
                    query not allowed
                </isEmpty>
            </isEmpty>
       </isEmpty>
   </dynamic>   另外,对查询表单的查询控制建议使用web层进行控制而不是客户端脚本(JAVASCRIPT/VBSCRIPT)

聚合函数常见问题
1。不要使用count(1)代替count(*)
2。count(column_name)计算该列不为NULL的记录条数
3。count(distinct column_name)计算该列不为NULL的不重复值数量
4。count()函数不会返回NULL,但sum()函数可能返回NULL,可以使用nvl(sum(qty),0)来避免返回NULL

NULL的使用
1。理解NULL的含义,是"不确定",而不是"空"
2。查询时,使用is null或者is not null
3。更新时,使用等于号,如:update tablename set column_name = null

STR2NUMLIST、STR2VARLIST函数的使用:
1。适用情况:使用唯一值(或者接近唯一值)批量取数据时,能够大大减少和数据库的交互次数

2。编写规范:a表必须放在from list的第一位,并且必须在select后加上下面的hint
  注意一:参数是由各个交易号拼成的字符串,以逗号间隔,不要有空格
  注意二:函数的参数是一个字符串,长度不能超过4000个字节
  注意三:函数生成的表只有一个字段,名字是column_value
  注意四:生成表的column_value字段是varchar2类型,如果希望是number类型,请使用str2numlist函数,并将vartabletype替换为numtabletype

   错误的写法(缺少hint):

select a.column_value, b.goods_title
     from TABLE(CAST(str2varlist(:1) as vartabletype)) a, beyond_trade_base b
    where a.column_value = b.trade_no;   错误的写法(函数生成的表必须放在from list的第一位):

select /*+ ordered use_nl(a,b) */ a.column_value, b.goods_title
     from beyond_trade_base b, TABLE(CAST(str2varlist(:1) as vartabletype)) a
    where a.column_value = b.trade_no;   正确的写法:

select /*+ ordered use_nl(a,b) */ a.column_value, b.goods_title
     from TABLE(CAST(str2varlist(:1) as vartabletype)) a, beyond_trade_base b
    where a.column_value = b.trade_no;   如果要求返回的结果记录条数和参数中交易号的个数一致,可使用外连接:

select /*+ ordered use_nl(a,b) */ a.column_value, b.goods_title
     from TABLE(CAST(str2varlist(:1) as vartabletype)) a, beyond_trade_base b
    where a.column_value = b.trade_no (+);   如果参数内的值不唯一,可能返回多行,而并不需要返回多行,可考虑使用聚合函数:

select /*+ ordered use_nl(a,b) */
       a.column_value, min(b.goods_title) goods_title
     from TABLE(CAST(str2varlist(:1) as vartabletype)) a, beyond_trade_base b
    where a.column_value = b.out_trade_no (+)
    group by a.column_value;   使用该函数与使用IN的区别:
    1。IN返回的结果是无序的,而该函数返回的结果是以参数中各值的顺序为顺序的
    2。IN返回的结果是不重复的,而该函数返回的结果可重复,取决于输入的参数

分页查询的使用
1。分页通常是先执行COUNT语句然后执行分页语句,当COUNT返回值为0的时候,应当避免执行后面的分页语句

2。有时,只须执行分页语句而无须执行COUNT语句,就不要执行COUNT语句,例如,用户下载excel格式的账户明细

3。有时,在分页前除了要统计COUNT还需要统计SUM,这些WHERE子句一致的统计应该在一条SQL中查出,而不是分多次统计

4。包含排序逻辑的分页查询写法,必须是三层select嵌套:

   错误的写法:

SELECT t1.*
     FROM (SELECT   t.*, ROWNUM rnum
               FROM beyond_trade_base t
              WHERE seller_account = :1
                AND gmt_create >= TO_DATE (:2, 'yyyy-mm-dd')
                AND gmt_create < TO_DATE (:3, 'yyyy-mm-dd')
           ORDER BY gmt_create DESC) t1
    WHERE rnum >= :4 AND rnum < :5   正确的写法:

SELECT t2.*
     FROM (SELECT t1.*, ROWNUM rnum
             FROM (SELECT   t.*
                       FROM beyond_trade_base t
                      WHERE seller_account = :1
                        AND gmt_create >= TO_DATE (:2, 'yyyy-mm-dd')
                        AND gmt_create < TO_DATE (:3, 'yyyy-mm-dd')
                   ORDER BY gmt_create DESC) t1
            WHERE ROWNUM <= :4) t2
    WHERE rnum >= :55。不包含排序逻辑的分页查询写法,则是两层select嵌套,但对rownum的范围指定仍然必须在不同的查询层次指定:

   错误的写法:

SELECT t1.*
     FROM (SELECT t.*, ROWNUM rnum
             FROM beyond_trade_base t
            WHERE seller_account = :1
              AND gmt_create >= TO_DATE (:2, 'yyyy-mm-dd')
              AND gmt_create < TO_DATE (:3, 'yyyy-mm-dd')) t1
    WHERE rnum >= :4 AND rnum <= :5   正确的写法:

SELECT t1.*
     FROM (SELECT t.*, ROWNUM rnum
             FROM beyond_trade_base t
            WHERE seller_account = :1
              AND gmt_create >= TO_DATE (:2, 'yyyy-mm-dd')
              AND gmt_create < TO_DATE (:3, 'yyyy-mm-dd')
              AND ROWNUM <= :4) t1
    WHERE rnum >= :56。注意下面两种写法的逻辑含义是不同的:

   按交易创建时间排序(倒序),然后再取前10条:

SELECT t2.*
     FROM (SELECT t1.*, ROWNUM rnum
             FROM (SELECT   t.*
                       FROM beyond_trade_base t
                      WHERE seller_account = :1
                        AND gmt_create >= TO_DATE (:2, 'yyyy-mm-dd')
                        AND gmt_create < TO_DATE (:3, 'yyyy-mm-dd')
                   ORDER BY gmt_create DESC) t1
            WHERE ROWNUM <= 10) t2
    WHERE rnum >= 1   随机取10条,然后在这10条中按照交易创建时间排序(倒序):

SELECT t1.*
     FROM (SELECT   t.*, ROWNUM rnum
               FROM beyond_trade_base t
              WHERE seller_account = :1
                AND gmt_create >= TO_DATE (:2, 'yyyy-mm-dd')
                AND gmt_create < TO_DATE (:3, 'yyyy-mm-dd')
                AND ROWNUM <= 10
           ORDER BY gmt_create DESC) t1
    WHERE rnum >= 17。先连接后分页与先分页后连接

   性能较差:

SELECT t2.*
     FROM (SELECT t1.*, ROWNUM rnum
             FROM (SELECT   a.*, b.receive_fee
                       FROM beyond_trade_base a, beyond_trade_process b
                      WHERE a.trade_no = b.trade_no(+)
                        AND a.seller_account = :1
                        AND a.gmt_create >= TO_DATE (:2, 'yyyy-mm-dd')
                        AND a.gmt_create < TO_DATE (:3, 'yyyy-mm-dd')
                   ORDER BY a.gmt_create DESC) t1
            WHERE ROWNUM <= :4) t2
    WHERE rnum >= :5   性能较好:

SELECT /*+ ordered use_nl(a,b) */
          a.*, b.receive_fee
     FROM (SELECT t2.*
             FROM (SELECT t1.*, ROWNUM rnum
                     FROM (SELECT   t.*
                               FROM beyond_trade_base t
                              WHERE seller_account = :1
                                AND gmt_create >= TO_DATE (:2, 'yyyy-mm-dd')
                                AND gmt_create < TO_DATE (:3, 'yyyy-mm-dd')
                           ORDER BY gmt_create DESC) t1
                    WHERE ROWNUM <= :4) t2
            WHERE rnum >= :5) a,
          beyond_trade_process b
    WHERE a.trade_no = b.trade_no(+)   后面这种写法的适用情况:
   a、where子句中的查询条件都是针对beyond_trade_base表的(否则得到的结果将不相同)
   b、关联beyond_trade_process表时,用的是该表的主键或者唯一键字段(否则将改变结果集的条数)


Add Comment 
分享到:
评论

相关推荐

    DB2常用SQL写法

    DB2还允许一些独特的SQL写法,例如,`AnyOneTable`表示任意一个存在的表,这在某些特定情况下非常有用。但需要注意,这种用法并不推荐在生产环境中频繁使用,因为可能会带来不必要的性能影响。 变量的声明和赋值在...

    SQL写法—数据修改

    ### SQL写法——数据修改:条件 INSERT ALL 与 INSERT FIRST 在数据库操作中,SQL(Structured Query Language)作为处理关系型数据库的标准语言,其功能强大且应用广泛。本文将详细介绍如何利用Oracle数据库中的...

    sql学习 索引去哪儿_请注意这写法是案例非笑话.sql

    sql学习 索引去哪儿_请注意这写法是案例非笑话.sql

    实现 Oracle 连接 SQL Server

    ### 实现 Oracle 连接 SQL Server 的方法...需要注意的是,在实际操作过程中可能会遇到各种各样的问题,比如权限问题、网络配置等,因此建议在配置过程中仔细检查每一个步骤,并参考官方文档或寻求专业技术人员的帮助。

    SQLServer2008连接字符串写法大全.docx

    ### SQL Server 2008连接字符串写法详解 #### 一、概述 在与SQL Server 2008进行交互时,正确设置连接字符串至关重要。连接字符串定义了应用程序如何与数据库建立通信,并包含了诸如服务器地址、数据库名称、身份...

    SQL Server存储过程基本语法

    以上内容主要介绍了 SQL Server 中存储过程中的一些基本语法和操作方法,包括变量定义及赋值、表和临时表的操作、循环以及条件语句等,这些知识点对于理解和使用 SQL Server 存储过程至关重要。

    SqlServer2005和SqlServer2000的JDBC连接驱动下载,DriverName和URL写法

    SqlServer2005和SqlServer2000连接驱动,我已经验证过没有问题, 2005 driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver" URL = "jdbc:sqlserver://localhost:1433;...一定要注意写法的差别。

    Hibernate_NSQL&HQL增删改操作

    这里需要注意的是,在HQL中,类名首字母通常大写,以区别于普通的Java变量或SQL字段名。 #### HQL与NSQL的区别 1. **语法风格**:HQL更加面向对象,语法结构与Java类及其属性紧密相关;而NSQL则遵循标准SQL语法。 ...

    sql 书写规范

    5. 索引的使用,避免对索引列进行计算,注意比较值与索引列数据类型的一致性。 6. 尽量避免相同语句由于书写格式的不同,而导致多次语法分析,尽量使用 Bind 变量。 7. 尽量使用共享的 SQL 语句。 8. 查询的 Where ...

    sql 优化语句的几个常用注意事项

    保证数据库性能的sql语句写法,注意事项,使得我们在书写时避免使数据库低效率的执行命令

    优化sql语句执行效率几点注意事项

    第三,注意SQL的写法。使用JOIN操作时,确保正确指定JOIN条件,并优先选择小表作为驱动表,以减少数据处理量。此外,避免在SELECT语句中使用*,而是明确指定需要的字段,这样可以减少数据传输量,提高执行效率。 第...

    navicatepremuim连接sqlserver数据库遇到问题及解决方法

    在配置Navicat Premium 的界面时,需要注意端口号的写法,正确的写法是将端口号写在 IP 地址后面,使用英文状态下的逗号分隔,例如:192.168.1.1,1433。 在配置了 Navicat Premium 的界面后,需要配置高级选项,...

    Sql语法转换为Oracle语法

    以下是具体的SQL语法转换的一些关键点: 1. 数据库对象命名:在SQL Server中,表和列名通常用方括号包围(如 `[TableName]` 和 `[ColumnName]`),而在Oracle中,它们用双引号包围(如 `"TableName"` 和 `"Column...

    sql分页查询几种写法

    需要注意的是,实际应用中还需要考虑数据库的具体版本和表结构,以及索引的设置,这些因素都可能影响分页查询的效率。 总的来说,选择哪种分页方法取决于数据库版本、数据量、索引策略以及对性能的要求。在SQL ...

    SQL SERVER查询时间条件式的写法

    总之,SQL SERVER中的时间条件式查询需要注意日期和时间的精确匹配,以及正确处理当前日期和时间范围。使用适当的函数和比较运算符,可以确保查询的准确性和效率。在实际应用中,还需要根据具体需求和数据结构,调整...

    mysql全文搜索 sql命令的写法

    MySQL全文搜索是数据库管理系统中的一种高级搜索功能,它允许用户...但要注意,为了优化性能和搜索结果,可能需要进行一些额外的配置和优化,例如调整`FULLTEXT`索引的最小词长、停用词列表,以及使用合适的分词算法。

    SqlServer2000触发器

    使用注意事项 - 触发器可能导致性能下降,因为它们增加了数据库操作的复杂性。 - 触发器中的事务处理必须谨慎,否则可能导致死锁或其他并发问题。 - 由于触发器是透明的,可能隐藏了业务逻辑,使得调试和维护变得...

    SQL 执行超长语句

    ### SQL执行超长语句详解 在数据库管理与开发过程中,编写SQL语句是必不可少的一环。...通过采取上述提到的一些策略和技术手段,可以有效缓解因超长SQL语句带来的问题与挑战,最终实现更高效的数据处理与分析能力。

    从两种SQL表连接写法来了解过去

    ANSI(美国国家标准局)注意到SQL的重要性,开始制定SQL的标准化,分为多个阶段,其中SQL 86和SQL 92是两个重要的里程碑。SQL 86标准的写法是早期数据库系统,如Oracle和DB2所采用的,而SQL 92标准则引入了更清晰、...

Global site tag (gtag.js) - Google Analytics