WITH在数据开发中的奇技淫巧

絮絮叨叨

笔者在常见的数据开发中,发现如果脚本需要产生中间表,或者说想要提升脚本性能,把这段中间表逻辑变为子查询,在人肉堆SQL生涯中,不外乎两种办法:

  1. CREATE TABLE tmp.tmpxxxxx AS

    优点:可以落物理表,验数时可追溯源头;

    缺点:多一次落盘操作,讲白了说多IO,造成大量磁盘和网络开销

  2. CACHE TABLE tmpxxxxx AS

    优点:中间数据广播到每个节点,加快下次调用中间表读取速度

    缺点:中间数据不可查,如果下游计算只调用一次,cache操作多一个stage浪费计算资源

讲重点-WITH是什么?

WITH AS短语,也叫做子查询部分(subquery factoring),可以定义一个SQL片断,该SQL片断会被整个SQL语句用到。可以使SQL语句的可读性更高,也可以在UNION ALL的不同部分,作为提供数据的部分。

对于UNION ALL,使用WITH AS定义了一个UNION ALL语句,当该片断被调用2次以上,优化器会自动将该WITH AS短语所获取的数据放入一个Temp表中。而提示meterialize则是强制将WITH AS短语的数据放入一个全局临时表中。很多查询通过该方式都可以提高速度

WITH有什么用?

提供一个子查询,供整个SQL调用,同时便于整个脚本维护

WITH 使用场景及用法

WTITH用法

WITH a AS(), b AS(), c AS () SELECT * FROM a,b,c;

1. WITH后面必须直接跟使用WITH的SQL语句(如select、insert、update等),否则,WITH将失效

即使用WITH 时,SQL不能出现分号,即如果使用WITH,在调用WITH生成子查询之前,均不能出现分号对SQL进行逻辑隔断

举个例子:

WITH a AS () DROP TABLE xxx; SELECT * FROM a;

以上这段代码在drop table xxx部分出现分号,即对整段SQL进行隔断操作,对WITH来说,如遇到隔断,WITH临时存储子查询将会失效

2. 如果WITH的表达式名称与某个数据表或视图重名,则紧跟在该WITH后面的SQL语句使用的仍然是WITH,当然,后面的SQL语句使用的就是数据表或视图了

`-- table1是一个实际存在的表

WITH
table1 as
(
​ SELECT * FROM persons WHERE age < 30
)
SELECT * FROM table1 – 使用了名为table1的公共表表达式
SELECT * FROM table1 – 使用了名为table1的数据表`

自引用 WITH 可以引用自身,也可以引用在同一 WITH 子句中预先定义的 WITH。不允许前向引用。

WITH 注意事项

不可以在WITH中使用以下语句

  1. COMPUTE 或 COMPUTE BY
  2. ORDER BY(除非指定了 TOP 子句)
  3. INTO
  4. 带有查询提示的 OPTION 子句
  5. FOR XML
  6. FOR BROWSE

如果将 WITH用在属于批处理的一部分的语句中,那么在它之前的语句必须以分号结尾,如下面的SQL所示:

DROP TABLE xxx; WITH a AS () SELECT * FROM a;

WITH优化案例

代码来源于灵犀项目-老代码子查询均用CACHE处理,优化后改为WITH

`set spark.sql.hive.mergeFiles=true;
ALTER TABLE {dyncobj.targetdb}.{dyncobj.targetable} DROP IF EXISTS PARTITION(dt=’{dyncobj.dimdt}’);

– 加工click_PV&click_UV
WITH tmp_table_click_message_box AS (
SELECT
​ event_id
​ ,CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN event_param ELSE SPLIT(event_param,’’)[0] END AS messagebox_id
​ ,CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN NULL ELSE SPLIT(event_param,’
’)[1] END AS message_type_id
​ ,CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN NULL ELSE SPLIT(event_param,’’)[2] END AS message_id
​ ,CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN NULL ELSE SPLIT(event_param,’
’)[3] END AS task_id
​ ,GROUPING_ID() AS lvl
​ ,COUNT(DISTINCT user_log_acct) AS click_uv
​ ,COUNT(1) AS click_pv
FROM
​ adm.adm_s14_glb_mtu_click_di
WHERE
​ dt = ‘{dyncobj.dimdt}’
​ AND bs = ‘APP’
​ AND regexp_replace(app_version, ‘\\\.’, ‘’) >= 2140
​ AND regexp_replace(build_version, ‘\\\.’, ‘’) >= 2140
​ AND event_id in (‘THA_MyMessage_MessageBox’,‘THA_MessageCenter_Message’,‘THA_PushMessage_OpenMessage’)
GROUP BY
​ event_id – 16
​ ,CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN event_param ELSE SPLIT(event_param,’’)[0] END – 8
​ ,CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN NULL ELSE SPLIT(event_param,’
’)[1] END – 4
​ ,CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN NULL ELSE SPLIT(event_param,’’)[2] END – 2
​ ,CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN NULL ELSE SPLIT(event_param,’
’)[3] END – 1
GROUPING SETS(
(event_id), – 01111 15
(event_id, CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN event_param ELSE SPLIT(event_param,’’)[0] END), – 00111 7
(event_id, CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN event_param ELSE SPLIT(event_param,’
’)[0] END, CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN NULL ELSE SPLIT(event_param,’’)[1] END), – 00011 3
(event_id, CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN event_param ELSE SPLIT(event_param,’
’)[0] END, CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN NULL ELSE SPLIT(event_param,’’)[1] END, CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN NULL ELSE SPLIT(event_param,’’)[2] END), – 00001 1
(event_id, CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN event_param ELSE SPLIT(event_param,’’)[0] END, CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN NULL ELSE SPLIT(event_param,’’)[1] END, CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN NULL ELSE SPLIT(event_param,’_’)[3] END) – 00010 2
) ),

– 加工引入订单及金额
tmp_table_click_message_box_ord AS (
SELECT
​ event_id
​ ,messagebox_id
​ ,message_type_id
​ ,message_id
​ ,task_id
​ ,GROUPING_ID() AS lvl
​ ,COUNT(DISTINCT CASE WHEN gmv_type=‘order’ THEN b.parent_sale_ord_id ELSE NULL END) AS parent_ord_nums
​ ,COUNT(DISTINCT CASE WHEN gmv_type=‘paid’ THEN b.parent_sale_ord_id ELSE NULL END) AS parent_paid_nums
​ ,COUNT(DISTINCT CASE WHEN gmv_type=‘order_paid’ THEN b.parent_sale_ord_id ELSE NULL END) AS parent_gmv_amount_nums
​ ,COUNT(CASE WHEN gmv_type=‘order’ THEN sale_ord_id ELSE NULL END) AS son_ord_nums
​ ,COUNT(CASE WHEN gmv_type=‘paid’ THEN sale_ord_id ELSE NULL END) AS son_paid_nums
​ ,COUNT(CASE WHEN gmv_type=‘order_paid’ THEN sale_ord_id ELSE NULL END) AS son_gmv_amount_nums
​ ,SUM(CASE WHEN gmv_type=‘order’ THEN gmv_amount ELSE 0 END) AS order_amount
​ ,SUM(CASE WHEN gmv_type=‘paid’ THEN gmv_amount ELSE 0 END) AS paid_amount
​ ,SUM(CASE WHEN gmv_type=‘order_paid’ THEN gmv_amount ELSE 0 END) AS order_paid_amount
​ ,COUNT(DISTINCT CASE WHEN gmv_type=‘valid’ THEN b.user_log_acct ELSE NULL END) AS valid_order_uv
FROM
(SELECT
​ event_id
​ ,report_time
​ ,event_param
​ ,CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN event_param ELSE SPLIT(event_param,’’)[0] END AS messagebox_id
​ ,CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN NULL ELSE SPLIT(event_param,’
’)[1] END AS message_type_id
​ ,CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN NULL ELSE SPLIT(event_param,’’)[2] END AS message_id
​ ,CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN NULL ELSE SPLIT(event_param,’
’)[3] END AS task_id
​ ,sale_ord_id AS parent_sale_ord_id
FROM
​ gdm.gdm_m14_thai_sku_all_opt_app
WHERE
​ dt = ‘{dyncobj.dimdt}’
​ AND regexp_replace(app_version, ‘\\\.’, ‘’) >= 2140
​ AND regexp_replace(build_version, ‘\\\.’, ‘’) >= 2140
​ AND event_id in (‘THA_MyMessage_MessageBox’,‘THA_MessageCenter_Message’,‘THA_PushMessage_OpenMessage’)
) a
LEFT OUTER JOIN
(
SELECT
​ sale_ord_id
​ ,parent_sale_ord_id
​ ,user_log_acct
​ ,SUM(gmv_amount) AS gmv_amount
​ ,gmv_type
FROM
​ adm.adm_s04_glb_trade_ord_det_sum
WHERE
​ dt = ‘{dyncobj.dimdt}’
​ AND gmv_type IN (‘order’, ‘paid’, ‘order_paid’,‘valid’)
GROUP BY
​ sale_ord_id
​ ,parent_sale_ord_id
​ ,gmv_type
​ ,user_log_acct
) b
ON a.parent_sale_ord_id = b.parent_sale_ord_id
GROUP BY
​ event_id
​ ,messagebox_id
​ ,message_type_id
​ ,message_id
​ ,task_id
GROUPING SETS(
(event_id),
(event_id, messagebox_id),
(event_id, messagebox_id, message_type_id),
(event_id, messagebox_id, message_type_id, message_id),
(event_id, messagebox_id, message_type_id, task_id)
) ),

– 加工新用户
tmp_table_click_message_box_new_users AS (
SELECT
​ event_id
​ ,messagebox_id
​ ,message_type_id
​ ,message_id
​ ,task_id
​ ,GROUPING_ID() AS lvl
​ ,COUNT(DISTINCT b.user_log_acct) AS new_uv
FROM
(
SELECT
​ event_id
​ ,CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN event_param ELSE SPLIT(event_param,’’)[0] END AS messagebox_id
​ ,CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN NULL ELSE SPLIT(event_param,’
’)[1] END AS message_type_id
​ ,CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN NULL ELSE SPLIT(event_param,’’)[2] END AS message_id
​ ,CASE WHEN event_id = ‘THA_MyMessage_MessageBox’ THEN NULL ELSE SPLIT(event_param,’
’)[3] END AS task_id
​ ,sale_ord_id AS parent_sale_ord_id
FROM
​ gdm.gdm_m14_thai_sku_all_opt_app
WHERE
​ dt = ‘{dyncobj.dimdt}’
​ AND regexp_replace(app_version, ‘\\\.’, ‘’) >= 2140
​ AND regexp_replace(build_version, ‘\\\.’, ‘’) >= 2140
​ AND event_id in (‘THA_MyMessage_MessageBox’,‘THA_MessageCenter_Message’,‘THA_PushMessage_OpenMessage’)
) a
LEFT OUTER JOIN
(
SELECT
​ parent_sale_ord_id
​ ,user_log_acct
FROM
​ adm.adm_s04_glb_trade_ord_det_sum
WHERE
​ dt = ‘{dyncobj.dimdt}’
​ AND gmv_type = ‘valid’ – 取有效下单用户
) b
ON a.parent_sale_ord_id = b.parent_sale_ord_id
INNER JOIN
(
SELECT
​ user_log_acct
FROM
​ gdm.gdm_m01_glb_userinfo_basic_da
WHERE
​ dt = ‘{dyncobj.dimdt}’
​ AND SUBSTR(user_reg_tm,1,10) = ‘{dyncobj.dimdt}’ – 取当天注册新用户
) c
ON TRIM(LOWER(b.user_log_acct)) = TRIM(LOWER(c.user_log_acct))
GROUP BY
​ event_id
​ ,messagebox_id
​ ,message_type_id
​ ,message_id
​ ,task_id
GROUPING SETS(
(event_id),
(event_id, messagebox_id),
(event_id, messagebox_id, message_type_id),
(event_id, messagebox_id, message_type_id, message_id),
(event_id, messagebox_id, message_type_id, task_id)
) )

INSERT OVERWRITE TABLE {dyncobj.targetdb}.{dyncobj.targetable} PARTITION (dt=’{dyncobj.dimdt}’)
SELECT
​ a.event_id
​ ,a.messagebox_id AS messagebox_id
​ ,CASE WHEN a.messagebox_id = ‘1’ THEN ‘物流盒子’
​ WHEN a.messagebox_id = ‘2’ THEN ‘营销盒子’
​ WHEN a.messagebox_id = ‘3’ THEN ‘通知盒子’
​ WHEN a.messagebox_id = ‘4’ THEN ‘咚咚盒子’
​ ELSE NULL END AS messagebox_type
​ ,a.message_type_id
​ ,a.message_id
​ ,a.task_id
​ ,click_uv
​ ,click_pv
​ ,parent_ord_nums
​ ,parent_paid_nums
​ ,parent_gmv_amount_nums
​ ,son_ord_nums
​ ,son_paid_nums
​ ,son_gmv_amount_nums
​ ,order_amount
​ ,paid_amount
​ ,order_paid_amount
​ ,valid_order_uv
​ ,new_uv
​ ,CASE WHEN a.lvl = 15 THEN 1
​ WHEN a.lvl = 7 THEN 2
​ WHEN a.lvl = 3 THEN 3
​ WHEN a.lvl = 1 THEN 4
​ WHEN a.lvl = 2 THEN 5
​ ELSE NULL END AS lvl
FROM
​ tmp_table_click_message_box a
LEFT OUTER JOIN tmp_table_click_message_box_ord b
ON
​ coalesce(a.task_id,‘kl999’) = coalesce(b.task_id,‘kl999’)
​ AND a.event_id = b.event_id
​ AND coalesce(a.message_id,‘kl999’) = coalesce(b.message_id,‘kl999’)
​ AND coalesce(a.message_type_id,‘kl999’) = coalesce(b.message_type_id,‘kl999’)
​ AND coalesce(a.messagebox_id,‘kl999’) = coalesce(b.messagebox_id,‘kl999’)
​ AND a.lvl = b.lvl
LEFT OUTER JOIN tmp_table_click_message_box_new_users c
ON
​ coalesce(a.task_id,‘kl999’) = coalesce(c.task_id,‘kl999’)
​ AND a.event_id = c.event_id
​ AND coalesce(a.message_id,‘kl999’) = coalesce(c.message_id,‘kl999’)
​ AND coalesce(a.message_type_id,‘kl999’) = coalesce(c.message_type_id,‘kl999’)
​ AND coalesce(a.messagebox_id,‘kl999’) = coalesce(c.messagebox_id,‘kl999’);
“”"`

代码不讲了,自己看

最后的最后

  1. 少落临时表,费时费力浪费IO
  2. 不要滥用CACHE,当然CACHE还是个好东西,注意CACHE打开方式
  3. WITH可弥补CACHE性能上的使用场景
  4. 还是那句话,SQL不是垒出来的!
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: MATLAB可以通过调用Excel COM对象来读取Excel数据,并使用MATLAB的绘图函数来绘制图形。 以下是一个简单的示例代码,用于读取Excel文件数据并绘制折线图: ```matlab % 读取Excel文件 excel = actxserver('Excel.Application'); workbook = excel.Workbooks.Open('data.xlsx'); sheet = workbook.Sheets.Item(1); range = sheet.UsedRange; data = range.Value; % 关闭Excel workbook.Close(false); excel.Quit(); % 提取数据并绘图 x = data(:,1); y = data(:,2); plot(x, y); xlabel('X'); ylabel('Y'); title('数据图'); ``` 在这个例子,我们首先使用`actxserver`函数创建一个Excel COM对象,然后打开Excel文件并选择要读取的工作表。使用`UsedRange`属性可以获取工作表使用的单元格范围,然后使用`Value`属性将数据读取到MATLAB。 读取数据后,我们可以使用MATLAB的绘图函数(例如`plot`)来绘制图形。在这个例子,我们使用第一列作为X轴数据,第二列作为Y轴数据,并添加一些标签和标题。 最后,我们需要关闭Excel COM对象,以释放资源并避免内存泄漏。这可以通过调用`Close`和`Quit`方法来完成。 ### 回答2: MATLAB是一款广泛应用于科学计算和工程设计等领域的软件,它可以快速读取Excel文件并进行数据分析和图形绘制。在本文,我们将介绍如何使用MATLAB读取Excel数据并绘图。 1. 读取Excel文件 MATLAB可以通过使用readtable函数轻松地读取Excel文件数据。readtable函数可以读取Excel文件的所有数据或指定工作表数据。 创建Excel文件: ![excel文件示例1](https://img-blog.csdn.net/20180425173105957?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGltaXRfZmFjdHVyZXI=) 代码: ```matlab table = readtable('data.xlsx'); %读取整个excel xls文件 % table = readtable('data.xlsx', 'sheet', 'Sheet1'); %读取data.xlsx文件的sheet1数据 data = table2cell(table); % 将 table 类型 转换为 cell 类型 ``` 2. 数据处理 在MATLAB,我们可以使用不同的数据处理方法,例如加,减,乘和除等运算。可以使用MATLAB的内置函数对这些数据进行各种类型的统计分析。如果我们要画图,通常需要做的数据处理有数据清洗、数据转换和数据缩放等。 例如,如果我们想要绘制Excel两个数字列的对比,那么就需要将这两列分别读取然后进行处理,生成新的比较数据列,再将新的列绘制在一个图表上。这些数据处理方法在MATLAB也非常容易实现。 3. 绘制图表 MATLAB支持各种类型的图表绘制,例如散点图,直方图,折线图,饼图和二维/三维图等。在本例,我们将展示如何绘制两列数据的对比图。 代码如下: ```matlab % 读取Excel文件 table = readtable('data.xlsx'); data = table2cell(table); % 提取需要比较的两列 col1 = cell2mat(data(:,1)); col2 = cell2mat(data(:,2)); % 绘制散点图 scatter(col1,col2); % 添加标题和标签 title('Comparison of two columns from Excel'); xlabel('X axis label'); ylabel('Y axis label'); % 设定X和Y坐标轴的范围 xlim([min(col1) max(col1)]); ylim([min(col2) max(col2)]); ``` 以上代码通过使用scatter函数生成散点图,为图表添加了标题和标签,并设定了X和Y轴的范围。 通过这篇文章,我们介绍了如何使用MATLAB读取Excel数据并绘制图表。MATLAB可以轻松将Excel文件数据读取到MATLAB命令窗口,并使用MATLAB的各种数据处理和图表绘制工具可视化数据。如果您经常需要处理和绘制Excel文件数据,使用MATLAB非常方便。 ### 回答3: MATLAB是一种非常简单、快速的数值计算与数据可视化软件。它可以轻松读取Excel文件数据,并且可以将这些数据拟合成人们所需要的更具有生动性和可视化的图像。 读取Excel数据及转换 MATLAB软件自带内置函数load(),可以直接读取Excel文件数据。首先,需要打开Excel文件,然后选择“另存为”类型为“CSV(逗号分隔)(*.csv)”,在保存的过程Excel表的“逗号”被视为分隔符号被存储为CSV文件(即数据以逗号分隔的形式存储在文件),进而可以读取和加载。 代码示例: filename = 'data.csv'; %文件名为data.csv delimiter = ','; %指明分隔符为"," startRow = 2; %数据从excel表格的第2行开始 formatSpec = '%f%f%f%f%f%f%f%f%[^\n\r]'; %读取出每列数据格式 fileID = fopen(filename,'r'); %以只读方式打开data.csv dataArray = textscan(fileID, formatSpec, 'Delimiter', delimiter,'HeaderLines', startRow-1, 'ReturnOnError', false); fclose(fileID); %关闭文件 Data = [dataArray{1:end-1}]; %读取表格数值型数据 textData = dataArray{end}; %读取表格字符数据 clearvars filename delimiter startRow formatSpec fileID dataArray ans; 实现数据可视化 在读取数据之后,可以对数据做一些运算或者改变展现形式(如某些),从而可以通过MATLAB进行更直观的图像展示。 代码示例: 1.绘制折线图 plot(Data(:,1),Data(:,5));%绘制第1列与第5列之间的折线 2.绘制散点图 scatter(Data(:,2),Data(:,5));%绘制第2列与第5列之间的散点图 3.绘制柱状图 bar(Data(:,3));%绘制第3列的柱状图 4.绘制饼状图 pie(Data(:,7));%绘制第7列的饼图 5.绘制3D图 mesh(Data(:,6),Data(:,4),Data(:,8)); %绘制第4、6和8列的三维坐标系 总结与展望 MATLAB读取Excel数据并绘图是一个相对简单但又十分实用的能。在实际应用数据可视化有助于我们更好的了解数据,从更快速和高效地获取我们所需要的信息,更精确地进行决策。 值得注意的是,MATLAB读取Excel并绘图也存在一些限制性,如对数据量大小、数据类型以及对于不符合默认条件的Excel文件格式等方面进行的处理等。因此,在实际使用过程,需了解Excel数据的具体格式,并合理使用MATLAB函数进行分析与展示。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值