MySQL和Oracle里面SQL转换
比较特殊的:
1. 原有 MySQL字段设置为 not null default ''
原因: ORACLE 数据库 不允许存空字符串, 认为它跟null是一样的 修改: 这种情况下, 在xml中, 我们暂时的处理办法是在xml中修改原先插入的空字符串变为固定格式的字符串, 格式为"NULL_大写的列名或者列名简称"
根据观察, 存为空的情况, 可能是指, 这些数据是 作为一种默认配置的设定 目前有修改的是 a. account_performance_info_daily表中的account_type字段 => 'NULL_TYPE' b. life_cycle_saas_attachment 表中的tenant字段 => 'NULL_TENANT'
具体业务逻辑碰到冲突的地方需要进行相应更改, 一般是在select以及不同的 type case 判断上
2. 有部分的sql 并没有写在xml中
这种情况可能是遇到了sql 语句 是: a. 存在了数据库表中 例: select TABLE_NAME as tableName, DELETE_SQL as deleteSql from custom_account_data_tables b. 代码里面动态拼出来的 customSql c. 根据model 上的注解, 通过反射, 动态拼出来的 例: DbSearchUtil
如果碰到不适配的语句时, 一般是在OracleUtil类中进行相关修改的
3. 同时删除2表的操作,进行了修改,变成了 2个删除语句.
例: accountMapper.deleteBenchMarkById(benchMarkIds); accountMapper.deleteBecnchMarkWeightById(benchMarkIds);
4. 不同的schema 在注入 DataSource的时候,进行一个设置.
hikariConfig.setConnectionInitSql("ALTER SESSION SET CURRENT_SCHEMA = " + schema);
有关语法的:
1. 在insert中有忽略 唯一索引检查的操作, 语法与mysql 不同
例: <insert id="insertPermissions" parameterType="java.util.List"> insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(acl_entry(user, object_id, data_id)) */ into acl_entry("USER", object_id, data_id) <foreach collection="list" item="element" index="index" separator="union all"> ( select #{element.user, jdbcType = VARCHAR}, #{element.objectId, jdbcType = INTEGER}, #{element.dataId, jdbcType = VARCHAR} from dual) </foreach> </insert>
关于jdbcType根据现有的数据库设定来看, 与java类型的设定建议统一如下:
与数字相关的数据库一般使用NUMBER类型, jdbcType统一使用 NUMERIC
Java Type | jdbcType |
---|---|
String | VARCHAR |
Boolean | NUMERIC |
Integer | NUMERIC |
Long | NUMERIC |
Double | NUMERIC |
Date | DATE |
DateTime | TIMESTAMP |
更多设置可以参考 http://www.mybatis.org/mybatis-3/apidocs/reference/org/apache/ibatis/type/JdbcType.html
2. SELECT * FROM ACCOUNT WHERE ID IN (1,2,3)
上述in的参数个数, Oracle 上限是1000个, 目前的处理办法是在OracleUtil中分批查询然后合并结果
3. Oracle 是大小写不敏感的, 如果不使用别名, 默认返回的列名会是全部大写
4. 列名显式引用 需要使用双引号
常量VARCHAR使用单引号, 使用 0 或者 1 查询, 映射到Boolean字段上, 使用 as 别名的时候, 在表名后面一定 不要 使用, 在列名后面 可以 使用, 在where条件中, 使用原始列名 查询 如果列名是关键词,那么需要使用双引号 显式使用 例: select "LEVEL" as "level" from life_cycle_saas_event_type a where a."LEVEL" = '母基金'
5. 根据条件进行删除的语句, delete 加上 join条件
例: <delete id="deleteRequirement"> delete from PRE_REQUIREMENT where rowid in ( select a.rowid from PRE_REQUIREMENT a left join pre_requirement_trace b on a.channel = b.channel where a.id = #{id} ) </delete>
6. 插入与更新操作中, 如果值可能为null, 需要显式指定jdbcType, 不然会报错. 例子见下一条.
7. 与mysql的replace into 语法相对应的写法如下
<insert id="moveInternalAccountsToDel" parameterType="com.datayes.mom.instance.attribution.AccountDel"> <!-- replace into account_del(ACCOUNT_ID, ACCOUNT_DATA, EXTERNAL_SOURCE) values <foreach collection="list" item="record" separator=","> (#{record.accountID}, \#{record.accountData}, \#{record.externalSource}) </foreach> Attention: Columns referenced in the ON Clause cannot be updated FOR ORACLE --> MERGE INTO account_del A USING ( <foreach collection="list" item="record" separator=" union all " index="index"> select #{record.accountID, jdbcType=VARCHAR} as accountID, #{record.accountData, jdbcType=VARCHAR} as accountData, #{record.externalSource, jdbcType=VARCHAR} as externalSource from dual </foreach> ) B ON (A.ACCOUNT_ID=B.accountID) WHEN MATCHED THEN UPDATE set A.ACCOUNT_DATA=B.accountData, A.EXTERNAL_SOURCE=B.externalSource WHEN NOT MATCHED THEN INSERT (ACCOUNT_ID, ACCOUNT_DATA, EXTERNAL_SOURCE) VALUES(B.accountID,B.accountData,B.externalSource)
</insert>
8. Oracle中的 分页查询参考下面的例子, 查询第2到11条数据
SELECT * FROM ACCOUNT OFFSET 1 ROWS FETCH NEXT 10 ROWS ONLY
9. 虽然在客户端中可以使用分号';'作为结尾, 但是在xml中使用分号将导致 sql 执行报错
10. 一些不同的函数
a. 获取今天的日期
SELECT TRUNC(sysdate, 'DD') FROM dual
b. 连接多个字符串
result.userName like '%' || #{keyword} || '%'
c. 映射到boolean的例子
d. regexp 正则匹配,对应 REGEXP_LIKE
REGEXP_LIKE(查询的字段,正则表达式)
11.插入时返回主键id
原语法
<insert id="insert" useGeneratedKeys="true" keyColumn="ID" keyProperty="id">
INSERT INTO xt_account_rule_info
(ACCOUNT_ID, ACCOUNT_CODE, ACCOUNT_NAME, ACCOUNT_SET_ID, ACCOUNT_SHEET_NAME, ACCOUNT_CELL, DATE_START_CELL,
UNIT_VALUE_START_CELL, ADJUST_VALUE_START_CELL, ACCUMULATE_VALUE_START_CELL)
VALUES
(#{accountId}, #{accountCode}, #{accountName}, #{accountSetId}, #{accountSheetName}, #{accountCell}, #{dateStartCell},
#{unitValueStartCell}, #{adjustValueStartCell}, #{accumulateValueStartCell})
</insert>
由于Oracle是不支持自动生成主键的,不像Sql或者Mysql能自动生成。所以 需要将 useGeneratedKeys 设置为false,并添加selectKey标签,查询对应的自增序列id并返回,如下:
<insert id="insert" useGeneratedKeys="false" keyColumn="ID" keyProperty="id">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Long">
SELECT
get_seq_curr(sequence_name)
FROM
user_tab_identity_cols
WHERE
table_name = UPPER('xt_account_rule_info')
</selectKey>
INSERT INTO xt_account_rule_info
(ACCOUNT_ID, ACCOUNT_CODE, ACCOUNT_NAME, ACCOUNT_SET_ID, ACCOUNT_SHEET_NAME, ACCOUNT_CELL, DATE_START_CELL,
UNIT_VALUE_START_CELL, ADJUST_VALUE_START_CELL, ACCUMULATE_VALUE_START_CELL)
VALUES
(#{accountId,jdbcType=VARCHAR}, #{accountCode,jdbcType=VARCHAR}, #{accountName,jdbcType=VARCHAR}, #{accountSetId}, #{accountSheetName,jdbcType=VARCHAR}, #{accountCell,jdbcType=VARCHAR}, #{dateStartCell,jdbcType=VARCHAR},
#{unitValueStartCell,jdbcType=VARCHAR}, #{adjustValueStartCell,jdbcType=VARCHAR}, #{accumulateValueStartCell,jdbcType=VARCHAR})
</insert>
12 不支持left 与 right函数
可以通过substr函数来进行替代
substr(字符串,截取开始位置,截取长度)
截取开始位置 = 负数时,表示截取的开始位置为字符串右端向左数第 截取长度 个字符
例如:
substr(str,0,2),等价于 left(str,2)
substr(str,-2,2),等价于 right(str,2)
替换公式如下:
right(str,len) -> substr(str,-len,len)
left(str,len) -> substr(str,0,len)
特别的,对于日期类型的截取,在mysql中可以直接使用left或者right函数进行操作,在oracle中,需要将对应的日期字段转换为标准的字符串内容后,再进行截取,比如:
在mysql中:
select left(curdate(),7) 可以得到:2022-02
在oracle中要使用substr替换
select substr(to_char(sysdate,'yyyy-MM-dd'),0,7) from dual;
13 char
对于char类型的字段,如果字段值实际长度小于字段设定长度,虽然肉眼看上去是没有空格的,但是实际上会在尾部补充空格,所以查询的时候,需要将字段trim之后或者将查询条件补充空格后进行查询。
不过一般来说,字段之所以定义为char类型,就是因为对应字段实际值会是定长的,所以一般也不需要额外的修改。对于一些特别的情况,可以按照上述方案,将查询字段添加trim函数后进行比较:TRIM(字段)=查询值
14 位运算
Oracle中只有位余运算:BITAND,表示返回两个数值型数值在按位进行 AND 运算后的结果。
语法:BITAND(nExpression1, nExpression2) BITAND将 nExpression1 的每一位同 nExpression2 的相应位进行比较。如果 nExpression1 和 nExpression2 的位都是 1,相应的结果位就是 1;否则相应的结果位是 0。
与:bitand,例如: bitand(7,1) 等价于 7 & 1
15 datediff函数
在oracle中没有datediff()函数 可以用以下方法在oracle中实现该函数的功能:
天:
ROUND(TO_NUMBER(END_DATE - START_DATE))
小时:
ROUND(TO_NUMBER(END_DATE - START_DATE) * 24)
分钟:
ROUND(TO_NUMBER(END_DATE - START_DATE) * 24 * 60)
秒:
ROUND(TO_NUMBER(END_DATE - START_DATE) * 24 * 60 * 60)
毫秒:
ROUND(TO_NUMBER(END_DATE - START_DATE) * 24 * 60 * 60 * 60)
getFundClose
16 CONCAT 函数
在mysql中 CONCAT函数可以拼接任意数量的参数
在oracle中,CONCAT函数仅接收两个参数的拼接,可用 || 替换
例如:
在mysql中,使用concat(1,2,3,4,5)
在oracle中,可替换为 1 || 2 || 3 || 4 || 5
17 oracle字段拼接过程中以0开头的小数,开头的0消失
为何小数点前0会省略,是因为oracle数据库中存在一个隐形类型转换,在拼接的过程中小数自动转成字符类型,相当于调用了to_char函数,所以丢失小数点前面的0
这里操作就是把数值类型转换为字符型,即加上to_char(字段,’fm9999999999999990.00’)
其中9代表如果存在数字则显示数字,不存在则显示空格; 0代表如果存在数字则显示数字,不存在则显示0,即占位符; fm代表删除如果是因9带来的空格,则删除。
18 时间差函数:timestampdiff
语法:timestampdiff(interval, datetime1,datetime2)
结果:返回(时间2-时间1)的时间差,结果单位由interval参数给出。
单位 | MySQL(UNIT) | oracle |
---|---|---|
毫秒 | ROUND(TO_NUMBER(END_DATE - START_DATE) * 24 * 60 * 60 * 60) | |
秒 | second | ROUND(TO_NUMBER(END_DATE - START_DATE) * 24 * 60 * 60) |
分钟 | minute | ROUND(TO_NUMBER(END_DATE - START_DATE) * 24 * 60) |
小时 | hour | ROUND(TO_NUMBER(END_DATE - START_DATE) * 24) |
天 | day | ROUND(TO_NUMBER(END_DATE - START_DATE)) |
周 | week | |
月 | month | trunc(months_between(END_DATE,START_DATE)) |
季 | quarter | |
年 | year | trunc(months_between(END_DATE,START_DATE)/12) |
19 中文排序问题
mysql 可以用过转换编码,达到使用中文拼音首字母排序的功能
order by convert ( 字段名 using gbk ) asc
在oracle中 可以使用
order by nlssort(字段名,'NLS_SORT=SCHINESE_PINYIN_M') asc
20 QUARTER() 函数,获取日期对应的季度
在mysql 中,QUARTER(日期字段) 函数返回给定日期值(从1到4的数字)的一年的四分之一。
-
1月至3月返回1
-
4月至6月返回2
-
7月至9月返回3
-
10月至12月返回4
在oracle中,可使用 to_char(日期字段,'Q') 替换
21 字符集不匹配问题
原因可能是字段类型不一致的原因,比如,两个字段一个是VARCHAR2,一个是NVARCHAR2
或者
是在union时,所联接的两块数据,对应的字段类型不一致,一边是VARCHAR2,一边是NVARCHAR2。
需要先对应到具体哪个字段不一致,然后其中一个进行转换。
目前遇到的情况,一般是查询中,有字段是写死的值, 用来做union或者与其他字段比较,而对应的字段是另一个数据类型。比如:
select nianyue,'全部' as VALUE_NAME_CN,count(1) shu
from (
SELECT distinct a.FUND_ID
,year(a.ESTABLISH_DATE)nianyue
from fund_class a
INNER JOIN fund_issue b on a.SECURITY_ID = b.SECURITY_ID and b.RAISE_METHOD = '1'
)a group by nianyue
select distinct a.FUND_ID
,year(b.ESTABLISH_DATE)nianyue
,d.VALUE_NAME_CN
from fund_class a
INNER JOIN fund_issue b on a.SECURITY_ID = b.SECURITY_ID and b.RAISE_METHOD = '1' and b.ESTABLISH_DATE is not null
join fund_type c on a.SECURITY_ID = c.SECURITY_ID and c.CODE_TYPE_ID = '40123'
join sys_code d on d.CODE_TYPE_ID = c.CODE_TYPE_ID and left(c.VALUE_NUM_CD,8) = d.VALUE_NUM_CD
以上两段sql中,VALUE_NAME_CN字段,上面的对应写死的值,下面的对应的实际字段,而实际字段的类型是NVARCHAR2,这个时候就会有字符集不一致的问题。
修改方案就是,将写死的值的类型转换一下就好了,Translate('全部' USING NCHAR_CS) as VALUE_NAME_CN
22 ORA-01799: 列不能外部联接到子查询
原因:Oracle 不支持 在 join中存在子查询,效率太低。
解决方案:先查询出关联表的关联列,条件列,以及其它需要的列,查询结果集作为一个表,再让其它表来关联这个结果集
例子:
修改前
SELECT DISTINCT a.PERSON_ID personId, g.manager_type investmentType
FROM (SELECT PERSON_ID, max(POSITION) POSITION
FROM fund_manager_new
WHERE POSITION = 'FM'
and PERSON_ID in <foreach collection="personIds" item="personId" open="(" close=")" separator=",">#{personId}</foreach>
GROUP BY PERSON_ID) a
LEFT JOIN fund_manager_rating_dy g ON a.PERSON_ID = g.PERSON_ID
AND g.END_DATE = (SELECT max(END_DATE) FROM fund_manager_rating_dy)
修改后
SELECT DISTINCT a.PERSON_ID personId, g.manager_type investmentType
FROM (SELECT PERSON_ID, max(POSITION) POSITION
FROM fund_manager_new
WHERE POSITION = 'FM'
and PERSON_ID in <foreach collection="personIds" item="personId" open="(" close=")" separator=",">#{personId}</foreach>
GROUP BY PERSON_ID) a
LEFT JOIN ( select PERSON_ID,manager_type from fund_manager_rating_dy
where END_DATE = (SELECT max(END_DATE) FROM fund_manager_rating_dy)) g
on a.PERSON_ID = g.PERSON_ID order by a.PERSON_ID
23 date_sub 函数
对应替换方式如下:
oracle | oracle | |
---|---|---|
增减一小时 | date_sub(createDate, interval -1 hour) date_sub(createDate, interval 1 hour) | createDate+1/24 createDate-1/24 |
增减一天 | date_sub(createDate, interval -1 day) date_sub(createDate, interval 1 day) | createDate+1 createDate-1 |
增减一月 | date_sub(createDate, interval -1 month) date_sub(createDate, interval 1 month) | add_months(createDate, 1) add_months(createDate, -1) |
增减一季度 | date_sub(createDate, interval -3 month) date_sub(createDate, interval 3 month) | add_months(createDate, 3) add_months(createDate, -3) |
增减一年 | date_sub(createDate, interval -1 year) date_sub(createDate, interval 1 year) | add_months(createDate, 12) add_months(createDate, -12) |
listagg(c.SEC_SHORT_NAME, ',') within
GROUP (order by rownum) as SEC_SHORT_NAME,
24 field 函数 自定义排序
ORACLE可以借助DECODE函数,自定义顺序排序:
DECODE(value,if 条件1,then 值1,if 条件2,then 值2,...,else 其他值)
例子:
mysql中自定义排序如下
ORDER BY FIELD(b.TYPE_NAME, '普通股票型', '偏股混合型', '短期纯债型', '中长期纯债型', '可转债型', '偏债混合型', '混合债券型(一级)', '混合债券型(二级)',
'平衡混合型', '灵活配置混合型', '被动指数股票型', '增强指数股票型', '被动指数债券型', 'QDII股票型', 'QDII债券型', 'QDII混合型', 'QDII其他',
'传统货币型', '短期理财型', '浮动净值型', 'FOF', 'REITs', '保本型', '传统封闭式', '商品型', '其他型')
等价于在oracle中的
ORDER BY DECODE(b.TYPE_NAME, '普通股票型', 1, '偏股混合型', 2, '短期纯债型', 3, '中长期纯债型', 4, '可转债型', 5,
'偏债混合型', 6, '混合债券型(一级)', 7, '混合债券型(二级)', 8,
'平衡混合型', 9, '灵活配置混合型', 10, '被动指数股票型', 11, '增强指数股票型', 12,
'被动指数债券型', 13, 'QDII股票型', 14, 'QDII债券型', 15, 'QDII混合型', 16, 'QDII其他', 17,
'传统货币型', 18, '短期理财型', 19, '浮动净值型', 20, 'FOF', 21, 'REITs', 22, '保本型', 23, '传统封闭式', 24, '商品型',25,
'其他型', 99)
25 date函数,截取日期
想将1997/1/8 10:30:27变为1997/1/8,在mysql中使用 date(时间字段)
在oracle中,使用 trunc(时间字段)
26 ORA-00907: 缺失右括号,子查询中不能有order by
oracle子查询中使用order by 会报错:ORA-00907: 缺失右括号
from 子句后面的内联视图是可以使用order by子句进行排序的。
所以,可以将对应的oder by 子查询语句再嵌套一层。
改造前
SELECT CLOSE_INDEX FROM
(( SELECT CLOSE_INDEX,TRADE_DATE FROM mkt_idxd
WHERE INDEX_ID = 1782 AND TRADE_DATE < #{date} ORDER BY TRADE_DATE DESC LIMIT 1)
UNION
(SELECT CLOSE_INDEX,TRADE_DATE FROM mkt_idxd
WHERE INDEX_ID = 1782 AND TRADE_DATE >= #{date} ORDER BY TRADE_DATE)) t
ORDER BY TRADE_DATE
改造后:
SELECT CLOSE_INDEX FROM
(( SELECT * from ( SELECT CLOSE_INDEX,TRADE_DATE FROM mkt_idxd
WHERE INDEX_ID = 1782 AND TRADE_DATE < #{date} and rownum=1 ORDER BY TRADE_DATE DESC ) a1 )
UNION
( SELECT * from (SELECT CLOSE_INDEX,TRADE_DATE FROM mkt_idxd
WHERE INDEX_ID = 1782 AND TRADE_DATE >= #{date} ORDER BY TRADE_DATE) a2) ) t
ORDER BY TRADE_DATE
改动点就是将原order by 子句,再嵌套一层,select * from table order by create_time 改为 select * from (原子句)
27 ORA-01791:不是SELECTed表达式
SQL 语句是先执行 distinct 去重后,再使用 order by 进行排序的。所以如果在 order by 需要排序的字段,没有在 distinct 后的字段中,就会抛错。
解决方案:
在 distinct 后加入需要排序的字段即可。
28 limit 问题
oracle 中没有limit,可以使用rownum替换
但是在语句中存在order by 排序时,单纯的将limit替换为rownum是不对的,因为rownum是在order by排序执行之前设置的值,针对带有order by的语句,需要使用 fetch first关键字进行替换
例如:
select SECURITY_ID from MD_SECURITY order by SECURITY_ID limit 1
转换为oracle
select SECURITY_ID from MD_SECURITY order by SECURITY_ID fetch first 1 rows only
即: 将 limit 替换为 fetch first {需要数据行数} rows only
详细内容可参考:https://www.cnblogs.com/CandiceW/p/10030936.html
to_date(sysdate)
29 CURDATE()函数
CURDATE()函数值为不包括时分秒的值,所以替换的时候,要替换为to_date(sysdate)
30 @自定义变量问题
lag与lead函数是跟偏移量相关的两个分析函数,通过这两个函数可以在一次查询中取出同一字段的前N行的数据(lag)和后N行的数据(lead)作为独立的列,从而更方便地进行进行数据过滤。这种操作可以代替表的自联接,并且LAG和LEAD有更高的效率。
over()表示 lag()与lead()操作的数据都在over()的范围内,他里面可以使用partition by 语句(用于分组) order by 语句(用于排序)。partition by a order by b表示以a字段进行分组,再 以b字段进行排序,对数据进行查询。
例如:lead(field, num, defaultvalue) field需要查找的字段,num往后查找的num行的数据,defaultvalue没有符合条件的默认值。
窗口分析函数:
sum() over ()
下面列一下开窗函数与分析函数搭配使用的情况:
1.有partition by有order by : 在partition by分组下,按照不同的order by 字段 实现递增汇总
2.有partition by无order by: 实现分组内所有数据的汇总
3.无partition by有order by : 直接按order by 字段实现递增汇总
4.无partition by无order by: 所有数据相加
当然,除了使用sum() over(),还有
count() over(partition by ... order by ...):求分组后的总数。 max() over(partition by ... order by ...):求分组后的最大值。 min() over(partition by ... order by ...):求分组后的最小值。 avg() over(partition by ... order by ...):求分组后的平均值。 lag() over(partition by ... order by ...):取出前n行数据。
lead() over(partition by ... order by ...):取出后n行数据。
原sql:
(SELECT z1.*,IF(z1.SECURITY_ID=@SECURITY_ID,cast(@shu as DECIMAL(20,4)),null) AS HOLD_VOLUME_z1,
@SECURITY_ID:=SECURITY_ID,@shu:= HOLD_VOLUME_z
from
(SELECT REPORT_DATE,SECURITY_ID,TICKER_SYMBOL,SEC_SHORT_NAME,TYPE_NAME,sum(HOLD_FUND) HOLD_FUND_z,sum(HOLD_INST) HOLD_INST_z,sum(MARKET_VALUE) MARKET_VALUE_z,sum(RATIO_IN_FLOAT_A) RATIO_IN_FLOAT_A_z,sum(HOLD_VOLUME) HOLD_VOLUME_z
from fund_mt_holdkey_type
where CATEGORY in <foreach collection="strategyCodes" item="code" open="(" close=")" separator=",">#{code}</foreach>
group by REPORT_DATE,SECURITY_ID,TICKER_SYMBOL,SEC_SHORT_NAME,TYPE_NAME
order by SECURITY_ID,REPORT_DATE) z1,(SELECT @SECURITY_ID:=NULL,@shu:= null)r)
改造后sql:
(SELECT
case when z1_pre = SECURITY_ID then HOLD_VOLUME_z1_1 end as HOLD_VOLUME_z1,
z1_1.*
from (SELECT lag(z1.SECURITY_ID, 1, null) over (order by SECURITY_ID,REPORT_DATE) as z1_pre,
lag(cast(z1.HOLD_VOLUME_z as DECIMAL(20,4)), 1, null) over (order by SECURITY_ID,REPORT_DATE) AS HOLD_VOLUME_z1_1,
z1.*
from
(SELECT REPORT_DATE,SECURITY_ID,TICKER_SYMBOL,SEC_SHORT_NAME,TYPE_NAME,sum(HOLD_FUND) HOLD_FUND_z,sum(HOLD_INST) HOLD_INST_z,sum(MARKET_VALUE) MARKET_VALUE_z,sum(RATIO_IN_FLOAT_A) RATIO_IN_FLOAT_A_z,sum(HOLD_VOLUME) HOLD_VOLUME_z
from fund_mt_holdkey_type
where CATEGORY in <foreach collection="strategyCodes" item="code" open="(" close=")" separator=",">#{code}</foreach>
group by REPORT_DATE,SECURITY_ID,TICKER_SYMBOL,SEC_SHORT_NAME,TYPE_NAME
order by SECURITY_ID,REPORT_DATE) z1) z1_1)
31 substring 函数
直接替换为substr函数即可
32 year 函数获取日期的年份
year ( 日期字段 )
转换为oracle函数为:
extract(year from 日期字段)
33 force index 强制使用索引
SELECT /*+index(t pk_emp)*/* FROM EMP T --强制索引,/*.....*/第一个星星后不能有空格,里边内容结构为:加号index(表名 空格 索引名)。 --如果表用了别名,注释里的表也要使用别名。
34 join时没有on或者where条件
使用join
或时inner join
,on
条件是可选的。这与ANSI标准不同,并且与几乎所有其他数据库不同。效果是cross join