zoukankan      html  css  js  c++  java
  • SQL语法粗整理

    1、在同一张表中,对前一条数据进行更新性插入操作,即:
      
    对上一条记录的部分属性(id, handledpeople, handledmessage, handledtime)进行更新操作,并将更新后的数据,在不改变原记录的情况下,插入到数据库中,此方法的SQL语句如下:
    insert into table select sys_guid(), userid, subjectid, applytime, applyreason, 'change_A', 'change_B', sysdate from table
    where handledtime = (select max(handledtime) from table where subjectid = 'f30c77cc-fd2a-49b1-a5dd-0e1b60505b1d');
    ps:其中id有唯一性约束,必须进行更新操作。
    此句SQL表示,查询指定的SUBJECTID条中HANDLEDTIME为最大的那条语句,进行更新部分字段的值后,将新结果插入到数据库中。
     
    2、Oracle中,对于日期的格式化有一下几种:
         a、输出日期时的格式化函数:
              to_char(date,'yyyy-MM-dd hh24:mi:ss')此为24小时格式,输出如:2014-10-10 09:20:30
              to_char(date,'yyyy-MM-dd hh12:mi:ss PM')此为24小时格式,输出如:10-10月-2014 09:20:30 上午
              b、存储为格式化的日期函数:
              to_data(date, 'yyyy-MM-dd hh24:mi:ss')其后格式同上
     
    3、关于SQL的执行效率的问题:
         有两条SQL语句,如下:
              a:select a.* from tableA a where a.id = (select b.Aid from tableB b where b.id = 'xxx')
              b:select a.id, a.name, a.age, a.gender from tableA a join tableB b on a.id = b.Aid where b.id = 'xxx'
         分析:从结果来看,两条sql的执行结果是一致的,都能从数据库中取得正确的结果集,但是,从效率来讲,b种写法比a种写法的执行效率更高。
     
    4、左关联、右关联以及全关联查询:
         左关联:left join on:左边表的查询结果全部显示,既是右边的条件不满足,也能显示,即以左表为中心,一切数据都为左表服务;
         右关联:right join on:右边的表为中心,为右表服务;
         全关联:join on:只有双方都得到满足时,数据方可显示出来,二表为平等关系;
     
    5、多表查询之效率(细节影响效率篇):
         a、FROM子句后面的表顺序:
              ORACLE在解析sql语句的时候对FROM子句后面的表名是从右往左解析的,是先扫描最右边的表,然后在扫描左边的表,然后用左边的表匹配数据,匹配成功后就合并。 所以,在对多表查询中,一定要把小表写在最右边;
              -- tableA:100w条记录 tableB:1w条记录
              select count(1) from tableA, tableB;
              select count(1) from tableB, tableA;(效率更高)
              还有一种是三张表的查询:
              select count(1) from tableA a,tableB b ,tableC c where a.id=b.id and a.id=c.id;
              上面中tableA 为交叉表,根据oracle对From子句从右向左的扫描方式,应该把交叉表放在最末尾,然后才是最小表,所以上面的应该这样写:
              -- tableA a 交叉表
      -- tabelB b 100w条记录
      --tableC c 1w条记录
      select count(1) from tableB b ,tableC c ,tableA a where a.id=b.id and a.id=c.id;
         b、Where子句后面的条件过滤:
              ORACLE对where子句后面的条件过滤是自下向上,从右向左扫描的,所以和From子句一样一样的,把过滤条件排个序,按过滤数据的大小,自然就是最少数据的那个条件写在最下面,最右边,依次类推,例如:
              --No.1 不可取 性能低下
      select * from tableA a where a.id>500 and a.lx = '2b' and a.id < (select count(1) from tableA where id=a.id);
      --No.2 性能高
      select * from tableA a where a.id < (select count(1) from tableA where id=a.id) and a.id>500 and a.lx = '2b';
         c、使用select的时候少用*,最好写上字段名,因为ORACLE的查询器会把*转换为表的全部列名,这个会浪费时间的,所以在大表中少用;
         d、充分利用rowid ,可以用rowid来分页,删除查询重复记录,效率很高的,如:
              --oracle查找重复记录
              select * from tableA a where a.rowid >= (select min(rowid) from tableB b where a.column = b.column);
              --oracle删除重复记录
              delete from tableA a where a.rowid>=(select min(rowid) from tableB b where a.column=b.column);
              --分页 start=10 limit=10
      --end 为 start + limit
      --1.查询要排列的表A
      --2.查询A表的Rownum找出小于end的数据组成表B
      --3.查询B表通过rownum找出大于start的数据完成
      --简单的说先根据end值过滤数据,然后在根据start过滤数据
      SELECT * FROM (SELECT a.*, ROWNUM rn FROM (SELECT * FROM uim_serv_file_data ORDER BY OUID) a where ROWNUM<=20) b
           where rn>10 order by ouid desc;
         e、存储过程中需要注意的,多用commit,可以释放资源,但是要谨慎;
         f、减少对数据库表的查询,尽量能程序实现的就不要使用sql操作;
         g、少用in,多用exists来代替,如:
              --NO.1 IN的写法
    SELECT *
    FROM TABLEA A
    WHERE A.ID IN (SELECT ID FORM TABLEB B WHERE B.ID > 1);
      --NO.2 exists 写法
    SELECT *
    FROM TABLEA A
    WHERE EXISTS(SELECT 1
                 FROM TABLEB B
                 WHERE A.ID = B.ID AND B.ID > 1);
     
    6、查询在一段时间内的指定数据:
         使用time相关的函数:to_char和to_date,如:
    SELECT
      appName,
      to_char(CREATETIME, 'yyyy-MM-dd') time
    FROM TABLE
    WHERE CREATETIME BETWEEN to_date('begintime', 'yyyy-MM-dd hh24:mi:ss') AND to_date('endtime', 'yyyy-MM-dd hh24:mi:ss')
    ORDER BY CREATETIME ASC;
         说明:查询createtime在begintime和endtime范围内的数据,并以createtime从小到大排序输出。
     
    7、多表查询:
         现有日志表,记录了用户申请APP的流程,如下:
        
         表结构为:用户没做一次申请的动作,便会产生一条记录;管理员每做一次审核的动作,便会在原来的记录的基础上产生一条新的记录,新记录的部分数据与原记录相同,但后半部分数据则与原数据不同。现在要求:查询出用户申请APP动作的最新的记录,如果管理员有审核,则按handledTime排序取最新的那条记录,如果管理员没有进行审核(此时的handledTime字段为null值),则取出用户单独操作的那条记录,查询语句如下(此语句中包含了关联的另一个表的数据,但无伤大雅):
    SELECT appName, applyTime, handledTime, handledMessage, handledResult FROM (
      SELECT
        s.NAME                                    appName,
        to_char(f.APPLYTIME, 'yyyy-MM-dd')        applyTime,
        to_char(f.HANDLEDTIME, 'yyyy-MM-dd')      handledTime,
        f.HANDLEDMESSAGE                          handledMessage,
        f.HANDLEDRESULT                           handledResult,
        dense_rank()
        OVER (PARTITION BY f.SUBJECTID
          ORDER BY f.HANDLEDTIME DESC NULLS LAST) o
      FROM API_APPLY_FLOW f, API_SUBJECT s
      WHERE f.SUBJECTID = s.ID AND s.USERID = '1f151f1ede88483eabf598fa77828a36'
    ) WHERE o = 1;
    至于执行效率,没有做过测试,不知道。
         ps:desc nulls last表示将null值放到排序序列的最后面,因为Oracle默认在时间排序中,null为最大值,如果没有此句,则取出的值与预期不符。对于MySQL,因为暂时没用所以就没测试。
     
    8、关于几个排序函数(rank() over、dense_rank()、row_number())之间的区别 :
      rank() over:相同行的排序结果相同,但占用排序的位数,即排序的结果不连续;
      dense_rank():相同行的排序结果相同,不占用排序的位数,排序结果是连续的;
      row_number():不考虑相同的行,一律顺序排次,排序结果当然也是连续的;
     
    9、查询指定的一段时期内,符合要求的记录的总数,要求按周进行统计:
    SELECT
      TO_CHAR(y.CREATE_TIME, 'yyyy') year,
      TO_CHAR(y.CREATE_TIME, 'iw')   week,
      COUNT(0)                       COUNT
    FROM WXF_YHXX y
    WHERE y.CREATE_TIME >= to_date('2016-08-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')
          AND y.CREATE_TIME < to_date('2016-09-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')
    GROUP BY TO_CHAR(y.CREATE_TIME, 'iw'), TO_CHAR(y.CREATE_TIME, 'yyyy')
    ORDER BY week DESC;

     

    10、一行转多列并进行关联查询:

      问题说明:现遇到,在查询主表时,有一列的字段类型为varchar,但是其所存的值,却是一个数组,格式为这样:'76,70,71,72,73,74,75,15',其中每一个数字,都为另一个表中对应的id的值。由于数据量很大,如果通过代码循环来做的话,对数据库的查询次数会呈笛卡儿积的形式增加,效率大大降低。所以,怎么通过一条sql语句来实现一次性查询呢?

      解决办法:oracle中有一个函数,叫做:REGEXP_*, 这类函数有四种形式,每一种的使用方法也不一样,介绍如下:

        1、REGEXP_REPLACE(),参数有六个,具体例子参见 这个

        2、REGEXP_LIKE()参数有三个,具体例子参见 这个

        3、REGEXP_INSTR(),参数有六个,参见 这个

        4、REGEXP_SUBSTR(),参数有五个,参见 这个

      现在,要针对性的解决问题了,具体SQL为:

    WITH a AS (SELECT '/ABC/AA/AD/ABD/JI/CC/ALSKD/ALDKDJ' id
               FROM dual) SELECT regexp_substr(id, '[^/]+', 1, rownum) id
                          FROM a
                          CONNECT BY rownum <= length(regexp_replace(id, '[^/]+'));

      实际的开发应用的是这个:

    SELECT REGEXP_SUBSTR(t.ITEM_IDS, '[^,]+', 1, LEVEL, 'i') item
    FROM (SELECT *
          FROM WXF_JCJL_SBXX sme
          WHERE sme.ID = '5995') t
    CONNECT BY LEVEL <= LENGTH(ITEM_IDS) - LENGTH(REGEXP_REPLACE(ITEM_IDS, ',', '')) + 1;

      说明:替换的字符为逗号(,),输出结果为:'76,70,71,72,73,74,75,15'这些全都拆开了。

     11、小问题:分页查询

      这是个最常见也最容易忽视的一个东西。分页的目的或作用是:一是为了使前端展示起来比较美观,二是提高了数据库的性能,减少了非必要数据的查询从而减少了资源的浪费。

      至于分页实现的原理什么的,戳这里

      现在来说说如何使用SQL语句来实现分页。分页的技术实现有好多种,不同数据库标准下的实现是不同的,现只针对ORACLE数据库进行说明,其他的出门右转有百度,左转有google,请自便。

      实现方式:继续戳,对,就这里。

      
    12、CASE ... WHEN ... THEN ... WHEN ... THEN ... ELSE ... END
      作为查询,有时候会遇到一些没有具体汉字属性的值,库里面存的只是一串数字或者其他乱七八糟的标识符号,这些东西要是传给前端,人家又不知道那什么意思,来回问来问去的也麻烦,还不如自己在SQL里就给定义好了省事。
      然后问题来了,怎么进行自定义返回的参数的值。现有CASE语句,便可解决这个问题。
      例子:    
    SELECT COMPANY_ID, STATE FROM WXF_JCJL ;
      查询结果为:
      
      其中STATE属性有两个值,分别为1和0,1代表“已经处理”,0代表“尚未处理”。
      使用CASE语句进行处理,方式为:
    SELECT
      COMPANY_ID,
      CASE STATE
      WHEN 1
        THEN '已经处理'
      WHEN 0
        THEN '尚未处理'
      ELSE '未知' END AS state
    FROM WXF_JCJL;

      结果为:

          

       这样看起来就好多了。
         需要注意的是,当 列名  放在CASE之后时,WHEN里面的值的类型必须要与列的类型一致,如果想要不一致,则将列名放到WHEN里就行了,此时的CASE后面是没有东西的。
     
     13、将多条名称重复, 但是个别字段不重复的记录, 合并为单条, 将重复的字段拼接为一行, 输出.
      这里的例子是:
        在table表中, companyName是companyAddress重复出现的列, name的值, 对于每个相同的companyName而言都是不同的, 现在要将companyName去重输出, name用符号拼接起来组成一个列, 并按照timeset的倒序排列输出:
    SELECT
      companyName,
      companyAddress,
      timeset,
      TRANSLATE(LTRIM(text, '/'), '*/', '*,') name
    FROM (SELECT
            ROW_NUMBER() OVER (PARTITION BY companyName ORDER BY companyName, lvl DESC) rn,
            companyName,
            companyAddress,
            timeset,
            text
          FROM (SELECT
                  companyName,
                  companyAddress,
                  timeset,
                  LEVEL                          lvl,
                  SYS_CONNECT_BY_PATH(name, '  ') text
                FROM
                  (SELECT
                        companyName,
                        companyAddress,
                        name,
                        timeset,
                        ROW_NUMBER() OVER (PARTITION BY companyName ORDER BY companyName, name) x
                      FROM
                        tableORDER BY companyName, timeset, name) a
                CONNECT BY companyName = PRIOR companyName AND x - 1 = PRIOR x))
    WHERE rn = 1
    ORDER BY timeset DESC 
     
     
  • 相关阅读:
    8月的list
    hdu 2853
    【问题交流】JAVA 基础 switch 执行顺序的问题
    h5/css动态旋转木马源码
    javascript系列丛书之读后感
    java运行闪退,报错如下,是因为ole32.dll的问题吗?
    js
    切换为文本框编辑状态,点击空白区域保存修改
    前端工程师源码分享:html5 2d 扇子
    2017武汉马拉松4月9日开跑啦~~~
  • 原文地址:https://www.cnblogs.com/SummerinShire/p/5940860.html
Copyright © 2011-2022 走看看