有序行转列

embedded/2024/11/15 5:45:54/

一、基础数据

有配送订单表记录骑手配送的物品类型、送达时间、顾客id、配送举例及配送费。

sql">+-----------+-----------+-------------+----------------------+--------------+-----------+----------+
| rider_id  | order_id  | goods_type  |    delivery_time     | customer_id  | distance  | payment  |
+-----------+-----------+-------------+----------------------+--------------+-----------+----------+
| r001      | 0001      | 食品          | 2024-01-01 08:30:00  | c001         | 8.05      | 7.50     |
| r002      | 0002      | 酒水          | 2024-01-01 08:43:00  | c003         | 3.01      | 13.00    |
| r003      | 0003      | 食品          | 2024-01-01 09:15:00  | c004         | 4.12      | 3.50     |
| r002      | 0004      | 文件          | 2024-01-01 09:21:00  | c005         | 10.98     | 15.00    |
| r001      | 0005      | 食品          | 2024-01-01 09:30:00  | c007         | 2.32      | 5.00     |
| r002      | 0006      | 食品          | 2024-01-01 09:47:00  | c002         | 0.78      | 5.00     |
| r003      | 0007      | 文件          | 2024-01-01 10:21:00  | c010         | 8.11      | 8.00     |
| r001      | 0008      | 酒水          | 2024-01-01 11:56:00  | c023         | 4.35      | 15.00    |
| r002      | 0009      | 电子产品        | 2024-01-01 12:30:00  | c031         | 5.05      | 9.50     |
| r002      | 0010      | 文件          | 2024-01-01 13:30:00  | c001         | 6.05      | 7.00     |
+-----------+-----------+-------------+----------------------+--------------+-----------+----------+

二、函数介绍

1.transform介绍

transform(expr, func) - 使用函数对数组中的元素进行转换。

Examples:

sql">> SELECT transform(array(1, 2, 3), x -> x + 1);[2,3,4]
> SELECT transform(array(1, 2, 3), (x, i) -> x + i);[1,3,5]

Since: 2.4.0

2.其他函数介绍

  • collect_list
  • collect_set
  • concat_ws

三、有序行转列

根据配送订单记录表,查询出骑手id,顾客id列表,要求顾客id列表中的顺序按照送达时间早晚排序。

分析

这里要求按照订单送达时间,对顾客id进行排序。直接考虑是使用开窗函数,根据时间进行排序(这种方法不可行,原因在于collect_list和collect_set那句提示“该函数是非确定性的,因为收集结果的顺序取决于行的顺序,这在经过shuffle之后可能是不确定的”。collect_list函数很难测试,但是collect_set因为有去重操作,所以比较好测试。另外一种解法是将时间和用户id拼接在一起,时间在前,用户id在后,这样对整个字符串拼接为数组,进行排序后再拆分,如此得到的数据能确定保证按照顺序完成。

1.不确定解法(不建议使用)

collect_list执行SQL

sql">select rider_id,delivery_time,customer_id,collect_list(customer_id)over(partition by rider_id order by delivery_time) as customer_id_list
from t_delivery_orders

collect_list执行结果

sql">+-----------+----------------------+--------------+---------------------------------------+
| rider_id  |    delivery_time     | customer_id  |           customer_id_list            |
+-----------+----------------------+--------------+---------------------------------------+
| r001      | 2024-01-01 08:30:00  | c001         | ["c001"]                              |
| r001      | 2024-01-01 09:30:00  | c007         | ["c001","c007"]                       |
| r001      | 2024-01-01 11:56:00  | c023         | ["c001","c007","c023"]                |
| r002      | 2024-01-01 08:43:00  | c003         | ["c003"]                              |
| r002      | 2024-01-01 09:21:00  | c005         | ["c003","c005"]                       |
| r002      | 2024-01-01 09:47:00  | c002         | ["c003","c005","c002"]                |
| r002      | 2024-01-01 12:30:00  | c031         | ["c003","c005","c002","c031"]         |
| r002      | 2024-01-01 13:30:00  | c001         | ["c003","c005","c002","c031","c001"]  |
| r003      | 2024-01-01 09:15:00  | c004         | ["c004"]                              |
| r003      | 2024-01-01 10:21:00  | c010         | ["c004","c010"]                       |
+-----------+----------------------+--------------+---------------------------------------+

collect_set执行SQL

sql">select rider_id,delivery_time,customer_id,collect_set(customer_id)over(partition by rider_id order by delivery_time) as customer_id_list
from t_delivery_orders

collect_set执行结果

sql">+-----------+----------------------+--------------+---------------------------------------+
| rider_id  |    delivery_time     | customer_id  |           customer_id_list            |
+-----------+----------------------+--------------+---------------------------------------+
| r001      | 2024-01-01 08:30:00  | c001         | ["c001"]                              |
| r001      | 2024-01-01 09:30:00  | c007         | ["c001","c007"]                       |
| r001      | 2024-01-01 11:56:00  | c023         | ["c001","c007","c023"]                |
| r002      | 2024-01-01 08:43:00  | c003         | ["c003"]                              |
| r002      | 2024-01-01 09:21:00  | c005         | ["c005","c003"]                       |
| r002      | 2024-01-01 09:47:00  | c002         | ["c005","c003","c002"]                |
| r002      | 2024-01-01 12:30:00  | c031         | ["c005","c003","c002","c031"]         |
| r002      | 2024-01-01 13:30:00  | c001         | ["c001","c005","c003","c002","c031"]  |
| r003      | 2024-01-01 09:15:00  | c004         | ["c004"]                              |
| r003      | 2024-01-01 10:21:00  | c010         | ["c010","c004"]                       |
+-----------+----------------------+--------------+---------------------------------------+

我们可以观察最后一行结果,发现顺序是不一样。 可以看到collect_list结果是正确的(这里属于巧合,但是大多数情况都是对的),而collect_set的结果是错误的。两个函数中均有提示,不保证结果顺序,从严谨出发,这两个函数均不可因为开窗函数来保证有序。
如果忽略该问题,使用collect_list进行行转列开窗,大部分情况得到的结果是正确的。我们只需要取出每个骑手最后一行数据即可。

执行SQL

sql">selectrider_id,concat_ws(',',customer_id_list) as customer_id_list
from
(select rider_id,delivery_time,customer_id,collect_list(customer_id)over(partition by rider_id order by delivery_time) as customer_id_list,row_number() over (partition by rider_id order by delivery_time desc) as rn
from t_delivery_orders) t
where rn = 1

执行结果

sql">+-----------+---------------------------+
| rider_id  |     customer_id_list      |
+-----------+---------------------------+
| r001      | c001,c007,c023            |
| r002      | c003,c005,c002,c031,c001  |
| r003      | c004,c010                 |
+-----------+---------------------------+

2.拼接排序后拆分

2.1先把时间和顾客id进行拼接,拼接后进行行转列

执行SQL

sql">select rider_id,delivery_time,customer_id,concat(delivery_time, customer_id) as time_customer
from t_delivery_orders

执行结果

sql">+-----------+----------------------+--------------+--------------------------+
| rider_id  |    delivery_time     | customer_id  |      time_customer       |
+-----------+----------------------+--------------+--------------------------+
| r001      | 2024-01-01 08:30:00  | c001         | 2024-01-01 08:30:00c001  |
| r002      | 2024-01-01 08:43:00  | c003         | 2024-01-01 08:43:00c003  |
| r003      | 2024-01-01 09:15:00  | c004         | 2024-01-01 09:15:00c004  |
| r002      | 2024-01-01 09:21:00  | c005         | 2024-01-01 09:21:00c005  |
| r001      | 2024-01-01 09:30:00  | c007         | 2024-01-01 09:30:00c007  |
| r002      | 2024-01-01 09:47:00  | c002         | 2024-01-01 09:47:00c002  |
| r003      | 2024-01-01 10:21:00  | c010         | 2024-01-01 10:21:00c010  |
| r001      | 2024-01-01 11:56:00  | c023         | 2024-01-01 11:56:00c023  |
| r002      | 2024-01-01 12:30:00  | c031         | 2024-01-01 12:30:00c031  |
| r002      | 2024-01-01 13:30:00  | c001         | 2024-01-01 13:30:00c001  |
+-----------+----------------------+--------------+--------------------------+
2.2 对time_customer 按照骑手id分组行转列,并使用sort_array排序

执行SQL

sql">select rider_id,sort_array(collect_list(time_customer)) as sorted_time_customer
from (select rider_id,delivery_time,customer_id,concat(delivery_time, customer_id) as time_customerfrom t_delivery_orders) t
group by rider_id

执行结果

sql">+-----------+----------------------------------------------------+
| rider_id  |                sorted_time_customer                |
+-----------+----------------------------------------------------+
| r001      | ["2024-01-01 08:30:00c001","2024-01-01 09:30:00c007","2024-01-01 11:56:00c023"] |
| r002      | ["2024-01-01 08:43:00c003","2024-01-01 09:21:00c005","2024-01-01 09:47:00c002","2024-01-01 12:30:00c031","2024-01-01 13:30:00c001"] |
| r003      | ["2024-01-01 09:15:00c004","2024-01-01 10:21:00c010"] |
+-----------+----------------------------------------------------+
2.3 去掉时间部分后,转换成字符串

执行SQL

sql">select rider_id,concat_ws(',', transform(sort_array(collect_list(time_customer)), x->substr(x, 20))) as customer_list
from (select rider_id,delivery_time,customer_id,concat(delivery_time, customer_id) as time_customerfrom t_delivery_orders) t
group by rider_id

执行结果

sql">+-----------+---------------------------+
| rider_id  |       customer_list       |
+-----------+---------------------------+
| r001      | c001,c007,c023            |
| r002      | c003,c005,c002,c031,c001  |
| r003      | c004,c010                 |
+-----------+---------------------------+

四、数据准备

sql">--建表语句
CREATE TABLE IF NOT EXISTS t_delivery_orders
(rider_id      string,         -- 骑手IDorder_id      string,         -- 订单IDgoods_type    STRING,         -- 物品类型delivery_time STRING,         -- 送达时间customer_id   STRING,         -- 客户iddistance      decimal(10, 2), -- 配送距离,单位可以是公里或英里payment       decimal(10, 2)  -- 支付金额,骑手的配送费用
)COMMENT '骑手配送订单表';
--插入数据
INSERT INTO t_delivery_orders VALUES
('r001', '0001', '食品', '2024-01-01 08:30:00','c001',8.05,7.50),
('r002', '0002', '酒水', '2024-01-01 08:43:00','c003',3.01,13.00),
('r003', '0003', '食品', '2024-01-01 09:15:00','c004',4.12,3.50),
('r002', '0004', '文件', '2024-01-01 09:21:00','c005',10.98,15.00),
('r001', '0005', '食品', '2024-01-01 09:30:00','c007',2.32,5.00),
('r002', '0006', '食品', '2024-01-01 09:47:00','c002',0.78,5.00),
('r003', '0007', '文件', '2024-01-01 10:21:00','c010',8.11,8.00),
('r001', '0008', '酒水', '2024-01-01 11:56:00','c023',4.35,15.00),
('r002', '0009', '电子产品', '2024-01-01 12:30:00','c031',5.05,9.50),
('r002', '0010', '文件', '2024-01-01 13:30:00','c001',6.05,7.00);

相关推荐

  1. 行转列-collect_list,collect_set进行简单行转列
  2. 行转列-使用transform进行有序行转列
  3. 行转列-使用transform进行有序行转列-多列一一对应
  4. 行转列-多行转多列(竖表转横表)
  5. 列转行-多列转多行(横表变竖表)
  6. 列转行-lateral view explode列转行
  7. 列转行-explode_outer和lateral view outer
  8. 列转行-posexplode多列对应转行
  9. 09.列转行-lateral view outer posexplode及posexplode_outer多列对应转行

http://www.ppmy.cn/embedded/105409.html

相关文章

hackme靶机攻略

1.通过nmap扫描靶场ip 2.目录扫描 3.找出文件存储位置,看看哪里可以上传文件 4.注册账号登录一下 点击search 5.输入1 and 11 -- 1 and 12 --看看有无SQL注入 6.判断字段数 1 order by 3 -- 说明字段数是3 7.查看数据库 -1 union select database(),2,3 # 8.查…

AI人工智能_Prompt提示词工程如何生成API接口文档

AI人工智能_Prompt提示词工程如何生成API接口文档?在与AI大模型的交互中,每当我们输入一段文字,无论是问题、命令还是陈述,这段文字就是一个Prompt。 Prompt提示词工程(Prompt Engineering)是一种技术或方…

奇异递归模板模式(Curiously Recurring Template Pattern)

奇异递归模板模式(Curiously Recurring Template Pattern) - 知乎 (zhihu.com) 本文来自上面的文章&#xff01;&#xff01;&#xff01;本菜鸡学习和记录一下。 CRTP是C模板编程时的一种惯用法&#xff1a;把派生类作为基类的模板参数。 1.静态多态 #include <iostrea…

【RabbitMQ】基本概念以及安装教程

1. 什么是MQ MQ( Message queue),从字面意思上看,本质是个队列,FIFO 先入先出&#xff0c;只不过队列中存放的内容是消息(message)而已.消息可以非常简单,比如只包含文本字符串,JSON等,也可以很复杂,比如内嵌对象.MQ多用于分布式系统之间进行通信 系统之间的调用通常有两种方式…

物联网(IoT)支持的小型水处理厂实时硬件在环(HIL)仿真

这篇论文的标题是《Real-Time Hardware-In-The-Loop Simulation of IoT-Enabled Mini Water Treatment Plant》&#xff0c;作者是 Mohamad Taib Miskon 等人&#xff0c;发表在 2024 年 IEEE 自动控制与智能系统国际会议&#xff08;I2CACIS&#xff09;上。以下是该论文的主要…

【C++拓展(一)】后端开发常用的技术栈

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; C拓展 1. 前言2. 语言层面3. 设计模式层面4. 开…

9.03.

#include <iostream>using namespace std;/*-------------------------------------------------------------*/ class RMB {static int count; private:int yuan;int jiao;int fen; public://获得当前RMB数量static int RMBNUM(){return count;}RMB(){count;}RMB(int yu…

django学习入门系列之第十点《django中数据库操作--创建与删除表》

文章目录 django创建与删除表开始创建表创建指令新增表删除表删除列新增列修改报错提示语言总结 往期回顾 django创建与删除表 删除表 创建表 修改表 操作目录 开始创建表 class text_into(models.Model):name models.CharField(max_length32)password models.CharField…