第十二章 - 条件判断(case when 和 if)和视图

文章介绍了SQL中用于条件判断的CASEWHEN和IF函数,以及视图的概念和用法。CASEWHEN提供了更灵活的多条件判断,而视图能简化复杂SQL并保护数据。通过示例展示了如何使用这些工具进行数据分类和格式转换,以及如何通过创建视图优化查询过程。

第十二章 - 条件判断(case when 和 if),和视图(view)

if 的用法

通过使用if函数可以实现数据二分类或者多分类的功能,比如按年龄区分青年、中年、老年,或者按价格区分价值等级等等,也是很常用的函数。
函数用法:当表达式成立时,返回a,否则就返回b。

if(表达式,a,b) 

举个例子:if的基本用法
按年龄段把用户分为年轻人和老年。

当年龄小于60岁的标记为年轻人,60岁(含60)以上的为老年人。

select
	name,
	age,
	if(age < 60,'年轻人','老年人') as '年龄段'
from
	test.titanic

输出结果:
在这里插入图片描述

if还可以嵌套使用

if ( 表达式 , if ( 表达式 , a1 , a2 ) , b )
或者
if ( 表达式 , a , if ( 表达式 , b1 , b2 ) )

举个例子:if嵌套使用
按年龄段把用户分为青年、中年、老年。
当年龄小于30岁时标记为青年,30岁到60岁以下的用户为中年,60岁以上(含60岁)的为老年

select
	name,
	age,
	if(age < 60,if(age < 30 , '青年','中年'),'老年') as '年龄段'
from
	test.titanic

输出结果:
在这里插入图片描述

case when 的用法

case when语句可以实现多条件判断,前面使用if虽然使用嵌套的方式也可以实现多条件判断,但是灵活性和代码可读性就低于case when语句。
case when 有两种用法,一种是固定值的用法,一种是表达式的用法,后一种用法更灵活也是最常用的一种。
用法1:不够灵活,不常用
以case开始,设置列名,当列内的值等于值1时返回a,等于值2时返回b,等于值3时返回c,…,(else表示当以上表达式都不满足时返回x。可不写,不写时返回null),最后以end结束

	case 列名
		when1 then a
        when2 then b
        when3 then c
        ....
        else x end 

用法2:使用灵活,常用
以case开始,满足表达式1返回a,满足表达式2返回b,满足表达式3返回c,…,(else表示当以上表达式都不满足时返回x。可不写)最后以end结束

	case 
		when 表达式1 then a
        when 表达式2 then b
        when 表达式3 then c
        ....
        else x end 

下面用case when语句实现if嵌套语句的例子
举个例子
按年龄段把用户分为青年、中年、老年。

select
	name,
	age,
	case 
		when age < 30 then '青年'
        when age < 60 then '中年'
        else '老年' end as '年龄段'
from
	test.titanic

输出结果:
在这里插入图片描述
和if嵌套实现的查询结果是一样的。

举个例子:使用正则匹配的case when
通过表达式匹配文本中对应季节的关键字,对服装进行季节的区分。

select
	title,
	case 
		when title regexp '春' then '春季'
	    when title regexp '夏' then '夏季'
	    when title regexp '秋' then'秋装'
	    when title regexp '冬' then '冬季'
	    else '其他' end as '季节分类'
from
	rectmall.product

输出结果:
在这里插入图片描述

视图(view)的用法

视图的作用就是把一个查询打包成一个虚拟的表。
视图的一些特点:

简化复杂的SQL:在一些复杂且有重复使用某些查询语句的情况下,可以大大简化SQL的操作。
数据保护:可一通过访问权限给予用户部分表的数据查询权限,而不是全部表的查询权限。
变更数据展示格式:可以在视图中修改数据的展示样式和格式。

语句格式:

create view 视图表名 as  查询语句

举个例子:
统计所有男性用户中,不同点击行为的数量。点击行为在behavior_log 表中,共四种行为 pv:浏览,cart加入购物车,fav:喜欢,buy:购买。用户性别在user_profile表中,1 为男性,2为女性。
非视图查询:

select
	case 
		when btag = 'pv' then '浏览'
	    when btag = 'cart' then "加购"
	    when btag = 'fav' then "喜欢"
	    when btag = 'buy' then "购买"
	    end as '行为',
	count(btag) as '数量'
from
	(
	select
		userid,
		final_gender_code,
		btag
	from
		user_profile as a left join behavior_log as b on a.userid = b.user
	 ) as temp
where 
	final_gender_code = 1
group by
	btag

输出结果:
在这里插入图片描述
作为一个合格的数据分析师,查询出来的数据还是要转换下显示样式,比如把字母缩写或者应为名称转换为中文格式显示。

这个查询结果是ok的,可是当我们还要再查询出女生的点击情况,或者每种浏览行为中的男女比例时呢。
这时候如果用视图来创建一个精简过的数据表,然后直接调用视图的化会不会更方便一些呢?下面我们来尝试一下。
先创建一个视图:

# 创建视图的时候可以直接就把数据做一个加工处理,这样在用到的时候看起来也会更方便一些。
create view behavior_table as
select
	userid as "用户ID",
	if(final_gender_code = 1 , "男","女") as "性别",
	case 
		when b.btag = 'pv' then '浏览'
	    when b.btag = 'cart' then "加购"
	    when b.btag = 'fav' then "喜欢"
	    when b.btag = 'buy' then "购买"
	    end as '行为'
from
	user_profile as a left join behavior_log as b on a.userid = b.user

创建好视图后,我们来先查看下视图中的数据样式。

# 查看视图中的数据
select
	*
from
	behavior_table

输出结果:
在这里插入图片描述
可以看到创建的视图behavior_table中,数据已经进行了格式的转换。
下面我们来使用视图去查询开始的问题(统计所有男性用户中,不同点击行为的数量。)

select
	`行为`,
	count(`行为`) as '计数'
from
	behavior_table
where 
	`性别` = '男'
group by
	`行为`

输出结果:
在这里插入图片描述
结果和之前是一样的。
下面再查询浏览行为中男女人数各多少。只需要直接通过创建的视图中去查询就可以了。

select
	`性别`,
	# 去重可以把重复的用户id去掉
	count(distinct `用户ID`) as '计数'
from
	behavior_table
where 
	`行为` = '浏览'
group by
	`性别`

输出数据:
在这里插入图片描述

视图的一些规则和限制:

  • 图名称必须是唯一的,不能与别的视图名字重复,也不能与表的名字重复。
  • 可创建视图的数目是没有限制的。
  • 视图是可以嵌套的,也就是说创建一个视图的时候可以使用别的是同中的数据来构造一个新的视图。
  • 视图不能索引,不能有关联的触发器。
  • 视图可以和表一起用,其实视图就是一个虚拟的表,可以和表做表连接。
REPORT ZBISMT_UPDATE. * 定义数据类型 TYPES: BEGIN OF ty_excel_data, matnr TYPE matnr, " 物料号 maktx TYPE maktx, " 物料描述(仅用于读取Excel,不处理) bismt TYPE bismt, " 库格 werks TYPE werks_d, " 工厂 lgort TYPE lgort_d, " 库位 END OF ty_excel_data. * 定义内表工作区 DATA: gt_excel_data TYPE TABLE OF ty_excel_data, gs_excel_data TYPE ty_excel_data, gt_zmm_bismt TYPE TABLE OF zmm_bismt, gs_zmm_bismt TYPE zmm_bismt, gt_updated TYPE TABLE OF zmm_bismt, " 存储更新的数据 gt_skipped TYPE TABLE OF zmm_bismt. " 存储跳过的数据(库格相同) * 保存结果到全局变量用于显示 DATA: gv_updated TYPE i, gv_skipped TYPE i, gv_inserted TYPE i. * 单物料维护相关变量 DATA: gv_edit_mode TYPE c, " 编辑模式:E=编辑,C=新建 gs_curr_data TYPE zmm_bismt. " 当前编辑的数据 * 选择屏幕定义 SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-t01. PARAMETERS: p_file TYPE rlgrap-filename. " Excel文件路径 PARAMETERS: p_werks TYPE werks_d DEFAULT '1011' OBLIGATORY. " 工厂输入 PARAMETERS: p_lgort TYPE lgort_d DEFAULT 'MT01' OBLIGATORY. " 库位输入 SELECTION-SCREEN SKIP. SELECTION-SCREEN BEGIN OF LINE. SELECTION-SCREEN COMMENT 1(20) TEXT-fil. " 文件选择标签 SELECTION-SCREEN PUSHBUTTON 21(15) but_file USER-COMMAND file_sel. " 文件选择按钮 SELECTION-SCREEN END OF LINE. PARAMETERS: p_test AS CHECKBOX DEFAULT 'X' USER-COMMAND test. " 测试模式开关 SELECTION-SCREEN END OF BLOCK b1. SELECTION-SCREEN SKIP. SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE TEXT-t02. PARAMETERS: p_matnr TYPE matnr. " 物料号输入 SELECTION-SCREEN SKIP. SELECTION-SCREEN BEGIN OF LINE. SELECTION-SCREEN PUSHBUTTON 1(10) but1 USER-COMMAND query. " 查询按钮 SELECTION-SCREEN PUSHBUTTON 12(10) but2 USER-COMMAND create. " 新建按钮 SELECTION-SCREEN PUSHBUTTON 23(10) but3 USER-COMMAND save. " 保存按钮 SELECTION-SCREEN END OF LINE. SELECTION-SCREEN SKIP. PARAMETERS: p_w_s TYPE werks_d MODIF ID dis, " 工厂(显示用) p_lg_s TYPE lgort_d MODIF ID dis, " 库位(显示用) p_bismt TYPE bismt MODIF ID edt. " 库格(可编辑) SELECTION-SCREEN END OF BLOCK b2. * 文本符号定义 INITIALIZATION. " 设置按钮文本 but1 = '查询'. but2 = '新建'. but3 = '保存'. but_file = '浏览...'. " 文件选择按钮文本 * 主程序 START-OF-SELECTION. " 只有在提供了文件路径时才执行批量更新 IF p_file IS NOT INITIAL. PERFORM read_excel_data. PERFORM process_data. PERFORM show_result. ELSE. " 显示提示信息,只有单物料维护被执行 WRITE: / '未提供Excel文件,跳过批量更新'. WRITE: / '仅执行了单物料维护功能'. ENDIF. *&---------------------------------------------------------------------* *& Form READ_EXCEL_DATA *&---------------------------------------------------------------------* FORM read_excel_data. DATA: lt_raw_data TYPE truxs_t_text_data. DATA: lt_temp_excel TYPE TABLE OF ty_excel_data. " 临时内表 " 检查文件是否存在 PERFORM check_file_existence USING p_file. " 调用函数上传Excel文件 CALL FUNCTION 'TEXT_CONVERT_XLS_TO_SAP' EXPORTING i_tab_raw_data = lt_raw_data i_filename = p_file TABLES i_tab_converted_data = lt_temp_excel " 先读到临时内表 EXCEPTIONS conversion_failed = 1 OTHERS = 2. IF sy-subrc <> 0. MESSAGE 'Excel文件读取失败' TYPE 'E'. ENDIF. " 从第二行开始读取数据(跳过标题行) LOOP AT lt_temp_excel INTO gs_excel_data FROM 2. " 使用用户输入的工厂库位值 gs_excel_data-werks = p_werks. gs_excel_data-lgort = p_lgort. APPEND gs_excel_data TO gt_excel_data. ENDLOOP. " 删除可能存在的空行(仅检查物料号) DELETE gt_excel_data WHERE matnr IS INITIAL. ENDFORM. " READ_EXCEL_DATA *&---------------------------------------------------------------------* *& Form PROCESS_DATA *&---------------------------------------------------------------------* FORM process_data. " 从目标表读取现有数据 SELECT matnr werks lgort bismt FROM zmm_bismt INTO TABLE gt_zmm_bismt. " 处理Excel数据 LOOP AT gt_excel_data INTO gs_excel_data. " 检查目标表中是否已存在相同物料号、工厂库位的记录 READ TABLE gt_zmm_bismt INTO gs_zmm_bismt WITH KEY matnr = gs_excel_data-matnr werks = gs_excel_data-werks lgort = gs_excel_data-lgort. IF sy-subrc = 0. " 记录已存在,检查库格是否相同 IF gs_zmm_bismt-bismt = gs_excel_data-bismt. " 库格相同,跳过不处理 gv_skipped = gv_skipped + 1. APPEND gs_zmm_bismt TO gt_skipped. ELSE. " 库格不同,准备更新记录 gs_zmm_bismt-bismt = gs_excel_data-bismt. " 仅在非测试模式下执行更新 IF p_test <> 'X'. UPDATE zmm_bismt SET bismt = gs_excel_data-bismt WHERE matnr = gs_excel_data-matnr AND werks = gs_excel_data-werks AND lgort = gs_excel_data-lgort. ENDIF. IF sy-subrc = 0 OR p_test = 'X'. gv_updated = gv_updated + 1. APPEND gs_zmm_bismt TO gt_updated. ENDIF. ENDIF. ELSE. " 新记录,准备插入 gs_zmm_bismt-matnr = gs_excel_data-matnr. gs_zmm_bismt-werks = gs_excel_data-werks. gs_zmm_bismt-lgort = gs_excel_data-lgort. gs_zmm_bismt-bismt = gs_excel_data-bismt. " 仅在非测试模式下执行插入 IF p_test <> 'X'. INSERT zmm_bismt FROM gs_zmm_bismt. ENDIF. IF sy-subrc = 0 OR p_test = 'X'. gv_inserted = gv_inserted + 1. ENDIF. ENDIF. ENDLOOP. " 仅在非测试模式下提交更改 IF p_test <> 'X'. COMMIT WORK. ENDIF. ENDFORM. " PROCESS_DATA *&---------------------------------------------------------------------* *& Form SHOW_RESULT *&---------------------------------------------------------------------* FORM show_result. DATA: lv_total TYPE i. DATA: ls_updated TYPE zmm_bismt. " 工作区用于显示 " 计算总记录数 DESCRIBE TABLE gt_excel_data LINES lv_total. " 显示测试模式提示 IF p_test = 'X'. WRITE: / '当前处于测试模式,不会实际修改数据库'. SKIP 1. ENDIF. WRITE: / '批量更新处理完成'. WRITE: / '总记录数:', lv_total. WRITE: / '更新记录数:', gv_updated. WRITE: / '跳过记录数(库格相同):', gv_skipped. WRITE: / '插入记录数:', gv_inserted. " 仅显示数量,不显示明细 " 显示所有更新记录 IF gv_updated > 0. WRITE: / '所有更新记录:'. WRITE: / '物料号', 20 '工厂', 27 '库位', 35 '原库格', 50 '新库格'. LOOP AT gt_updated INTO ls_updated. " 获取原库格值用于显示 READ TABLE gt_zmm_bismt INTO gs_zmm_bismt WITH KEY matnr = ls_updated-matnr werks = ls_updated-werks lgort = ls_updated-lgort. IF sy-subrc = 0. WRITE: / ls_updated-matnr, 20 ls_updated-werks, 27 ls_updated-lgort, 35 gs_zmm_bismt-bismt, " 原库格 50 ls_updated-bismt. " 新库格 ENDIF. ENDLOOP. ENDIF. " 显示所有跳过记录 IF gv_skipped > 0. WRITE: / '所有跳过记录(库格相同):'. WRITE: / '物料号', 20 '工厂', 27 '库位', 35 '库格'. LOOP AT gt_skipped INTO gs_zmm_bismt. WRITE: / gs_zmm_bismt-matnr, 20 gs_zmm_bismt-werks, 27 gs_zmm_bismt-lgort, 35 gs_zmm_bismt-bismt. ENDLOOP. ENDIF. ENDFORM. " SHOW_RESULT *&---------------------------------------------------------------------* *& Form CHECK_FILE_EXISTENCE *&---------------------------------------------------------------------* FORM check_file_existence USING p_filename. DATA: lv_file TYPE string. DATA: lv_exists TYPE abap_bool. lv_file = p_filename. " 使用GUI前端服务检查文件是否存在 CALL METHOD cl_gui_frontend_services=>file_exist EXPORTING file = lv_file RECEIVING result = lv_exists EXCEPTIONS cntl_error = 1 error_no_gui = 2 OTHERS = 3. IF sy-subrc <> 0 OR lv_exists <> abap_true. MESSAGE '文件不存在或无法访问' TYPE 'E'. ENDIF. ENDFORM. " CHECK_FILE_EXISTENCE *&---------------------------------------------------------------------* *& AT SELECTION-SCREEN OUTPUT *&---------------------------------------------------------------------* AT SELECTION-SCREEN OUTPUT. " 控制单物料维护区域字段状态 PERFORM control_single_mat_fields. *&---------------------------------------------------------------------* *& AT SELECTION-SCREEN *&---------------------------------------------------------------------* AT SELECTION-SCREEN. " 处理按钮事件 CASE sy-ucomm. WHEN 'QUERY'. PERFORM handle_query. WHEN 'CREATE'. PERFORM handle_create. WHEN 'SAVE'. PERFORM handle_save. WHEN 'FILE_SEL'. " 文件选择按钮事件 PERFORM handle_file_selection. ENDCASE. *&---------------------------------------------------------------------* *& Form CONTROL_SINGLE_MAT_FIELDS *&---------------------------------------------------------------------* FORM control_single_mat_fields. " 设置显示字段属性 LOOP AT SCREEN. IF screen-group1 = 'DIS'. " 显示字段设为只读 screen-input = 0. MODIFY SCREEN. ELSEIF screen-group1 = 'EDT'. " 库格字段:编辑模式下可编辑 IF gv_edit_mode IS NOT INITIAL. screen-input = 1. ELSE. screen-input = 0. ENDIF. MODIFY SCREEN. ENDIF. ENDLOOP. ENDFORM. " CONTROL_SINGLE_MAT_FIELDS *&---------------------------------------------------------------------* *& Form HANDLE_QUERY *&---------------------------------------------------------------------* FORM handle_query. " 检查物料号是否输入 IF p_matnr IS INITIAL. MESSAGE '请输入物料号' TYPE 'S' DISPLAY LIKE 'E'. RETURN. ENDIF. " 检查物料号是否存在 PERFORM check_matnr_exists USING p_matnr. " 检查物料在指定工厂库位是否存在 SELECT SINGLE * FROM zmm_bismt INTO gs_curr_data WHERE matnr = p_matnr AND werks = p_werks AND lgort = p_lgort. IF sy-subrc = 0. " 存在,进入编辑模式 gv_edit_mode = 'E'. p_w_s = gs_curr_data-werks. p_lg_s = gs_curr_data-lgort. p_bismt = gs_curr_data-bismt. MESSAGE s000(zmsg) WITH '物料已存在,进入编辑模式'. ELSE. " 不存在 CLEAR: p_w_s, p_lg_s, p_bismt. gv_edit_mode = ''. MESSAGE '该工厂库位不存在该物料' TYPE 'S' DISPLAY LIKE 'E'. ENDIF. ENDFORM. " HANDLE_QUERY *&---------------------------------------------------------------------* *& Form HANDLE_CREATE *&---------------------------------------------------------------------* FORM handle_create. " 检查物料号是否输入 IF p_matnr IS INITIAL. MESSAGE '请输入物料号' TYPE 'S' DISPLAY LIKE 'E'. RETURN. ENDIF. " 检查物料号是否存在 PERFORM check_matnr_exists USING p_matnr. " 检查是否已存在 SELECT SINGLE * FROM zmm_bismt INTO gs_curr_data WHERE matnr = p_matnr AND werks = p_werks AND lgort = p_lgort. IF sy-subrc = 0. " 已存在,进入编辑模式 gv_edit_mode = 'E'. p_w_s = gs_curr_data-werks. p_lg_s = gs_curr_data-lgort. p_bismt = gs_curr_data-bismt. MESSAGE s000(zmsg) WITH '物料已存在,自动进入编辑模式'. ELSE. " 不存在,进入新建模式 gv_edit_mode = 'C'. p_w_s = p_werks. p_lg_s = p_lgort. CLEAR p_bismt. MESSAGE s000(zmsg) WITH '进入新建模式,请填写库格'. ENDIF. ENDFORM. " HANDLE_CREATE *&---------------------------------------------------------------------* *& Form HANDLE_SAVE *&---------------------------------------------------------------------* FORM handle_save. " 检查是否在编辑模式 IF gv_edit_mode IS INITIAL. MESSAGE '请先查询或新建物料' TYPE 'S' DISPLAY LIKE 'E'. RETURN. ENDIF. " 检查库格是否填写 IF p_bismt IS INITIAL. MESSAGE '库格不能为空' TYPE 'S' DISPLAY LIKE 'E'. RETURN. ENDIF. " 设置数据 gs_curr_data = VALUE #( matnr = p_matnr werks = p_w_s lgort = p_lg_s bismt = p_bismt ). " 根据模式保存 CASE gv_edit_mode. WHEN 'E'. " 编辑模式 UPDATE zmm_bismt SET bismt = p_bismt WHERE matnr = p_matnr AND werks = p_w_s AND lgort = p_lg_s. IF sy-subrc = 0. MESSAGE '物料更新成功' TYPE 'S'. ELSE. MESSAGE '物料更新失败' TYPE 'S' DISPLAY LIKE 'E'. ENDIF. WHEN 'C'. " 新建模式 INSERT zmm_bismt FROM gs_curr_data. IF sy-subrc = 0. MESSAGE '物料创建成功' TYPE 'S'. ELSE. MESSAGE '物料创建失败' TYPE 'S' DISPLAY LIKE 'E'. ENDIF. ENDCASE. " 重置编辑模式 gv_edit_mode = ''. ENDFORM. " HANDLE_SAVE *&---------------------------------------------------------------------* *& Form CHECK_MATNR_EXISTS *&---------------------------------------------------------------------* FORM check_matnr_exists USING p_matnr. " 检查物料主数据是否存在 SELECT SINGLE matnr FROM mara INTO @DATA(lv_matnr) WHERE matnr = @p_matnr. IF sy-subrc <> 0. MESSAGE '物料号不存在' TYPE 'S' DISPLAY LIKE 'E'. gv_edit_mode = ''. CLEAR: p_w_s, p_lg_s, p_bismt. STOP. ENDIF. " 检查库存视图是否存在 SELECT SINGLE matnr FROM mard INTO @lv_matnr WHERE matnr = @p_matnr AND werks = @p_werks AND lgort = @p_lgort. IF sy-subrc <> 0. MESSAGE '物料在指定工厂库位的库存视图不存在' TYPE 'S' DISPLAY LIKE 'W'. ENDIF. ENDFORM. " CHECK_MATNR_EXISTS *&---------------------------------------------------------------------* *& Form HANDLE_FILE_SELECTION *&---------------------------------------------------------------------* FORM handle_file_selection. DATA: lt_file_table TYPE filetable, lv_rc TYPE i, lv_action TYPE i. " 调用文件选择对话框 CALL METHOD cl_gui_frontend_services=>file_open_dialog EXPORTING window_title = '选择Excel文件' default_extension = 'XLS' file_filter = 'Excel文件 (*.XLS;*.XLSX)|*.XLS;*.XLSX|所有文件 (*.*)|*.*|' CHANGING file_table = lt_file_table rc = lv_rc user_action = lv_action EXCEPTIONS file_open_dialog_failed = 1 cntl_error = 2 error_no_gui = 3 not_supported_by_gui = 4 OTHERS = 5. IF sy-subrc = 0 AND lv_action = cl_gui_frontend_services=>action_ok. " 获取用户选择的第一个文件 READ TABLE lt_file_table INDEX 1 INTO p_file. IF sy-subrc = 0. " 更新屏幕字段值 p_file = p_file. ENDIF. ENDIF. ENDFORM. " HANDLE_FILE_SELECTION 更改代码,现在读取文件只有物料号库格两列,物料描述被我去掉了
最新发布
08-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

煜岐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值