oracle-analysis

痛定思痛。 2023-10-18 16:02 197阅读 0赞

oracle-analysis

  1. CREATE TABLE EMPLOY
  2. (
  3. NAME VARCHAR2(10), --姓名
  4. DEPT VARCHAR2(10), --部门
  5. SALARY NUMBER --工资
  6. );
  7. INSERT INTO EMPLOY VALUES ('张三','市场部',4000);
  8. INSERT INTO EMPLOY VALUES ('赵红','技术部',2000);
  9. INSERT INTO EMPLOY VALUES ('李四','市场部',5000);
  10. INSERT INTO EMPLOY VALUES ('李白','技术部',5000);
  11. INSERT INTO EMPLOY VALUES ('王五','市场部',NULL);
  12. INSERT INTO EMPLOY VALUES ('王蓝','技术部',4000);
  13. SELECT
  14. ROW_NUMBER() OVER(ORDER BY SALARY) AS 序号,
  15. NAME AS 姓名,
  16. DEPT AS 部门,
  17. SALARY AS 工资
  18. FROM EMPLOY;
  19. /*
  20. 查询结果如下:
  21. 序号 姓名 部门 工资
  22. 1 赵红 技术部 2000
  23. 2 张三 市场部 4000
  24. 3 王蓝 技术部 4000
  25. 4 李四 市场部 5000
  26. 5 李白 技术部 5000
  27. 6 王五 市场部 (null)
  28. */
  29. SELECT
  30. ROW_NUMBER() OVER( ORDER BY DEPT) AS 序号,
  31. NAME AS 姓名,
  32. DEPT AS 部门,
  33. SALARY AS 工资
  34. FROM EMPLOY;
  35. /*
  36. 如果不在over中加入限制分组/作用域,那就是默认整个集合
  37. ROW_NUMBER() 从下面的序号一列中可以看出
  38. 1 赵红 技术部 2000
  39. 2 李白 技术部 5000
  40. 3 王蓝 技术部 4000
  41. 4 王五 市场部
  42. 5 张三 市场部 4000
  43. 6 李四 市场部 5000
  44. */
  45. SELECT
  46. ROW_NUMBER() OVER(PARTITION BY dept ORDER BY DEPT) AS 序号,
  47. NAME AS 姓名,
  48. DEPT AS 部门,
  49. SALARY AS 工资
  50. FROM EMPLOY;
  51. /*
  52. 加上PARTITION BY dept 根据部门重新排序
  53. 1 赵红 技术部 2000
  54. 2 李白 技术部 5000
  55. 3 王蓝 技术部 4000
  56. 1 王五 市场部
  57. 2 张三 市场部 4000
  58. 3 李四 市场部 5000
  59. */
  60. SELECT
  61. ROW_NUMBER() OVER(ORDER BY dept,SALARY NULLS first) AS 序号,
  62. NAME AS 姓名,
  63. DEPT AS 部门,
  64. SALARY AS 工资,
  65. round(AVG(SALARY) OVER(PARTITION BY dept),2) AS 部门平均工资,
  66. AVG(SALARY) OVER() AS 公司平均工资
  67. FROM EMPLOY;
  68. /*
  69. 加上nulls first后可以使得null的数据排在前面,
  70. 因为这里加上了(AVG(SALARY) OVER(PARTITION BY dept),2)
  71. 但也是排在部门的前面
  72. 1 赵红 技术部 2000 3666.67 4000
  73. 2 王蓝 技术部 4000 3666.67 4000
  74. 3 李白 技术部 5000 3666.67 4000
  75. 4 王五 市场部 4500 4000
  76. 5 张三 市场部 4000 4500 4000
  77. 6 李四 市场部 5000 4500 4000
  78. */
  79. SELECT
  80. ROW_NUMBER() OVER(ORDER BY SALARY DESC NULLS FIRST) AS RN,
  81. RANK() OVER(ORDER BY SALARY DESC NULLS FIRST) AS RK,
  82. DENSE_RANK() OVER(ORDER BY SALARY DESC NULLS FIRST) AS D_RK,
  83. NAME AS 姓名,
  84. DEPT AS 部门,
  85. SALARY AS 工资
  86. FROM EMPLOY;
  87. /*
  88. rank函数的作用是排名,如果有并列的名次那么会直接跳到下一名,但是DENSE_RANK就不会了,并列的名次,下面的名次依旧只是加一
  89. 查询结果如下:
  90. RN RK D_RK 姓名 部门 工资
  91. 1 1 1 王五 市场部 (null)
  92. 2 2 2 李四 市场部 5000
  93. 3 2 2 李白 技术部 5000
  94. 4 4 3 张三 市场部 4000
  95. 5 4 3 王蓝 技术部 4000
  96. 6 6 4 赵红 技术部 2000
  97. */
  98. SELECT
  99. NAME AS 姓名,
  100. SALARY AS 工资,
  101. SUM(SALARY) OVER(ORDER BY SALARY NULLS FIRST
  102. ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS 小于本人工资的总额,
  103. SUM(SALARY) OVER(ORDER BY SALARY NULLS FIRST
  104. ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS 大于本人工资的总额,
  105. SUM(SALARY) OVER(ORDER BY SALARY NULLS FIRST
  106. ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS 工资总额1,
  107. SUM(SALARY) OVER() AS 工资总额2
  108. FROM EMPLOY;
  109. DELETE FROM EMPLOY;
  110. INSERT INTO EMPLOY VALUES ('张三','市场部',2000);
  111. INSERT INTO EMPLOY VALUES ('赵红','技术部',2400);
  112. INSERT INTO EMPLOY VALUES ('李四','市场部',3000);
  113. INSERT INTO EMPLOY VALUES ('李白','技术部',3200);
  114. INSERT INTO EMPLOY VALUES ('王五','市场部',4000);
  115. INSERT INTO EMPLOY VALUES ('王蓝','技术部',5000);
  116. SELECT
  117. NAME AS 姓名,
  118. DEPT AS 部门,
  119. SALARY AS 工资,
  120. FIRST_VALUE(SALARY IGNORE NULLS) OVER(PARTITION BY DEPT) AS 部门最低工资,
  121. NTH_VALUE(SALARY, 2) OVER(PARTITION BY DEPT) AS 部门倒数第二工资,
  122. LAST_VALUE(SALARY RESPECT NULLS) OVER(PARTITION BY DEPT) AS 部门最高工资,
  123. SUM(SALARY) OVER(ORDER BY SALARY ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS "ROWS",
  124. SUM(SALARY) OVER(ORDER BY SALARY RANGE BETWEEN 500 PRECEDING AND 500 FOLLOWING) AS "RANGE"
  125. FROM EMPLOY;
  126. /*
  127. rows查询结果
  128. 查询结果如下:
  129. 姓名 工资 小于本人工资的总额 大于本人工资的总额 工资总额1 工资总额2
  130. 王五 (null) (null) 20000 20000 20000
  131. 赵红 2000 2000 20000 20000 20000
  132. 张三 4000 6000 18000 20000 20000
  133. 王蓝 4000 10000 14000 20000 20000
  134. 李四 5000 15000 10000 20000 20000
  135. 李白 5000 20000 5000 20000 20000
  136. ROWS BETWEEN <上限条件> AND <下限条件>
  137. 其中“上限条件”可以是如下关键字:
  138. UNBOUNDED PRECEDING
  139. <number> PRECEDING
  140. CURRENT ROW
  141. “下线条件”可以是如下关键字:
  142. CURRENT ROW
  143. <number> FOLLOWING
  144. UNBOUNDED FOLLOWING
  145. 以上关键字都是相对当前行的,UNBOUNDED PRECEDING表示当前行前面的所有行,也就是说没有上限;<number> PRECEDING表示从当前行开始到它前面的<number>行为止,例如,number=2,表示的是当前行前面的2行;CURRENT ROW表示当前行
  146. range查询结果
  147. 查询结果如下:
  148. 姓名 部门 工资 部门最低工资 部门倒数第二工资 部门最高工资 ROWS RANGE
  149. 张三 市场部 2000 2000 3000 4000 4400 4400
  150. 赵红 技术部 2400 3200 5000 2400 7400 4400
  151. 李四 市场部 3000 2000 3000 4000 8600 6200
  152. 李白 技术部 3200 3200 5000 2400 10200 6200
  153. 王五 市场部 4000 2000 3000 4000 12200 4000
  154. 王蓝 技术部 5000 3200 5000 2400 9000 5000
  155. 上面SQL的RANGE子句的作用是定义一个工资范围,这个范围的上限是当前行的工资-500,下限是当前行工资+500。例如:李四的工资是3000,所以上限是3000-500=2500,下限是3000+500=3500,那么有谁的工资在2500-3500这个范围呢?只有李四和李白,所以RANGE列的值就是3000(李四)+3200(李白)=6200。以上就是ROWS和RANGE得区别。
  156. 上面的 SQL 还用到了FIRST_VALUE,NTH_VALUE 和 LAST_VALUE 三个函数,它们的作用也非常简单,用来求OVER定义集合的最小值,第 n 行的值和最大值。值得注意的是这两个函数有个关键字,IGNORE NULLS 或 RESPECT NULLS,它们的作用正如它们的名字一样,用来忽略NULL值和考虑NULL值。
  157. */
  158. SELECT
  159. NAME AS 姓名,
  160. SALARY AS 工资,
  161. LAG(SALARY,0) OVER(ORDER BY SALARY) AS LAG0,
  162. LAG(SALARY) OVER(ORDER BY SALARY) AS LAG1,
  163. LAG(SALARY,2) OVER(ORDER BY SALARY) AS LAG2,
  164. LAG(SALARY,3 ,0) IGNORE NULLS OVER(ORDER BY SALARY) AS LAG3,
  165. LAG(SALARY,4, -1) RESPECT NULLS OVER(ORDER BY SALARY) AS LAG4,
  166. LEAD(SALARY) OVER(ORDER BY SALARY) AS LEAD
  167. FROM EMPLOY;
  168. /*
  169. 姓名 工资 LAG0 LAG1 LAG2 LAG3 LAG4 LEAD
  170. 张三 2000 2000 (null) (null) 0 -1 2400
  171. 赵红 2400 2400 2000 (null) 0 -1 3000
  172. 李四 3000 3000 2400 2000 0 -1 3200
  173. 李白 3200 3200 3000 2400 2000 -1 4000
  174. 王五 4000 4000 3200 3000 2400 2000 5000
  175. 王蓝 5000 5000 4000 3200 3000 2400 (null)
  176. 解释:
  177. LAG(表达式或字段,偏移量, 默认值) IGNORE NULLS或RESPECT NULLS
  178. LAG是向下偏移,LEAD是向上偏移
  179. */
  180. CREATE TABLE price_history
  181. (
  182. security_id NUMBER(10, 0),
  183. price NUMBER(10, 4),
  184. price_date DATE,
  185. rank NUMBER(2, 0)
  186. /*
  187. 存放股票历史价格
  188. */
  189. );
  190. CREATE TABLE price
  191. (
  192. security_id NUMBER(10, 0),
  193. price NUMBER(10, 4)
  194. /*
  195. 存放最新价格
  196. */
  197. );
  198. insert all
  199. into price_history(security_id,price,price_date,rank) values(1,10,CURRENT_DATE,1)
  200. into price_history(security_id,price,price_date,rank) values(1,8,CURRENT_DATE-1,3)
  201. into price_history(security_id,price,price_date,rank) values(1,9,CURRENT_DATE+1,2)
  202. into price_history(security_id,price,price_date,rank) values(2,10,CURRENT_DATE,2)
  203. into price_history(security_id,price,price_date,rank) values(2,11,CURRENT_DATE-1,1)
  204. into price_history(security_id,price,price_date,rank) values(3,13,CURRENT_DATE+2,3)
  205. into price_history(security_id,price,price_date,rank) values(3,10,CURRENT_DATE-1,1)
  206. into price_history(security_id,price,price_date,rank) values(3,10,CURRENT_DATE+2,2)
  207. into price_history(security_id,price,price_date,rank) values(2,10,CURRENT_DATE-2,3)
  208. into price_history(security_id,price,price_date,rank) values(4,10,CURRENT_DATE,2)
  209. into price_history(security_id,price,price_date,rank) values(4,10,CURRENT_DATE+3,3)
  210. into price_history(security_id,price,price_date,rank) values(4,10,CURRENT_DATE-1,1)
  211. select CURRENT_DATE from dual;
  212. select * from price_history;
  213. MERGE INTO price p
  214. USING (
  215. SELECT security_id, price FROM (
  216. SELECT
  217. ROW_NUMBER() OVER(PARTITION BY security_id ORDER BY price_date DESC, rank DESC) AS ROW_ID,
  218. security_id,
  219. price
  220. FROM
  221. price_history
  222. ) WHERE ROW_ID = 1
  223. ) ph
  224. ON (p.security_id = ph.security_id)
  225. WHEN MATCHED THEN UPDATE SET p.price = ph.price
  226. WHEN NOT MATCHED THEN INSERT VALUES (ph.security_id, ph.price);
  227. /*
  228. 以下是对上述语句的解释
  229. */
  230. /*下面的集合按照security_id编号,在相同的security_id里面会从1开始编码*/
  231. SELECT
  232. ROW_NUMBER() OVER(PARTITION BY security_id ORDER BY price_date DESC, rank DESC) AS ROW_ID,
  233. security_id,
  234. price
  235. FROM
  236. price_history
  237. /*然后选出相同的security_id,也就是row_id为1*/
  238. SELECT security_id, price FROM (
  239. SELECT
  240. ROW_NUMBER() OVER(PARTITION BY security_id ORDER BY price_date DESC, rank DESC) AS ROW_ID,
  241. security_id,
  242. price
  243. FROM
  244. price_history
  245. ) WHERE ROW_ID = 1
  246. /*最后使用merge语句,如果满足条件也就是在最新价格表中存在记录,我们就更新,没有就插入*/
  247. MERGE INTO price p
  248. USING (
  249. SELECT security_id, price FROM (
  250. SELECT
  251. ROW_NUMBER() OVER(PARTITION BY security_id ORDER BY price_date DESC, rank DESC) AS ROW_ID,
  252. security_id,
  253. price
  254. FROM
  255. price_history
  256. ) WHERE ROW_ID = 1
  257. ) ph
  258. ON (p.security_id = ph.security_id)
  259. WHEN MATCHED THEN UPDATE SET p.price = ph.price
  260. WHEN NOT MATCHED THEN INSERT VALUES (ph.security_id, ph.price);
  261. SELECT
  262. security_id,
  263. price_date,
  264. price,
  265. price - NVL(LAG(price) OVER(PARTITION BY security_id ORDER BY price_date), 0)
  266. FROM price_history;
  267. /*
  268. 假设现在我们有下面的表用来存放交易记录,现在我们要做一个报表,查询一下每相邻两次交易记录的 price 的差值,也就是第二条记录的 price 减去第一条的 price,第三条减去第二条
  269. 我们可以利用lag进行向下偏移,然后使用当前价格减去上一条记录的价格
  270. 1 2019-03-23 12:02:57 8 8
  271. 1 2019-03-24 12:02:57 10 2
  272. 1 2019-03-25 12:02:57 9 -1
  273. 2 2019-03-22 12:02:57 10 10
  274. 2 2019-03-23 12:02:57 11 1
  275. 2 2019-03-24 12:02:57 10 -1
  276. 3 2019-03-23 12:02:57 10 10
  277. 3 2019-03-26 12:02:57 10 0
  278. 3 2019-03-26 12:02:57 13 3
  279. 4 2019-03-23 12:02:57 10 10
  280. 4 2019-03-24 12:02:57 10 0
  281. 4 2019-03-27 12:02:57 10 0
  282. */

发表评论

表情:
评论列表 (有 0 条评论,197人围观)

还没有评论,来说两句吧...

相关阅读