在 MaxCompute 中日期类型包括 3 个:
2026-01-01 00:00:01 无法区别前后顺序区别如下:
-- 如果日期格式为 yyyy-mm-dd、yyyy-mm-dd hh:mi:ss 等可以直接转化成对应的类型,无需
SELECT DATE('2026-01-01')
,DATETIME('2021-11-29 00:01:00')
,TIMESTAMP('2021-01-11 00:00:00.123456789')
,CAST("2005-03-30" AS DATE)
,CAST("2005-03-30 00:00:00" AS DATETIME)
,CAST("2005-03-30 00:00:00" AS TIMESTAMP)
-- 。yyyy-mm-dd hh:mi:ss
-- 日期加减。年: yyyy, 月: mm, 天: dd, 小时: hh, 分钟: mi, 秒: ss
-- 扩展格式。年: year, 月: month 或 -mon, 日: day, 小时: hour
,DATEADD(DATETIME('2021-11-29 00:01:00'),-1,'yyyy')
,DATEADD(DATETIME('2021-11-29 00:01:00'),-1,'year')
,DATEADD(DATETIME('2021-11-29 00:01:00'),-1,'mm')
,DATEADD(DATETIME('2021-11-29 00:01:00'),-1,'month')
,DATEADD(DATETIME('2021-11-29 00:01:00'),-1,'mon')
,DATEADD(DATETIME('2021-11-29 00:01:00'),-1,'dd')
,DATEADD(DATETIME('2021-11-29 00:01:00'),-1,'day')
,DATEADD(DATETIME('2021-11-29 00:01:00'),-1,'hh')
,DATEADD(DATETIME('2021-11-29 00:01:00'),-1,'hour')
,DATEADD(DATETIME('2021-11-29 00:01:00'),-1,'mi')
,DATEADD(DATETIME('2021-11-29 00:01:00'),-1,'ss')
-- 如果想直接使用 STRING 类型,格式需符合 yyyy-mm-dd hh:mi:ss,同时添加配置
SET odps.sql.type.system.odps2=false;
SELECT DATEADD('2005-02-28 00:00:00', 1, 'dd');
-- 日期和时间戳互相转化。时间戳单位为 秒
unix_timestamp(datetime|date|timestamp|string <date>)
from_unixtime(bigint <unixtime>)常用操作
TO_CHAR(DATEADD(TO_DATE('${bizdate}','yyyymmdd'),-3,'month'),'yyyymmdd')-- 格式化为 年月日
TO_CHAR(create_time,'yyyymmdd')
-- 格式化为 年月日时分秒
TO_CHAR(chat_start_time,'yyyy-mm-dd hh:mi:ss')-- 获取某个日期所在的周一和周日,周一以 monday 开始
SELECT DATE_ADD(NEXT_DAY(DATETIME('2026-04-10 10:02:03'),'Monday'),-7)
,DATE_ADD(NEXT_DAY(DATETIME('2026-04-10 10:02:03'),'Monday'),-1)
;
-- 获取某个日期所在的周一和周日,周一以 friday 开始
SELECT DATE_ADD(NEXT_DAY(DATETIME('2026-04-10 10:02:03'),'Friday'),-7)
,DATE_ADD(NEXT_DAY(DATETIME('2026-04-10 10:02:03'),'Friday'),-1)
;
-- 上面的 sql 不仅在 ODPS 中有效,在 Doris 中也有效假设有 1 张订单表,查询用户首次下单的订单id、下单时间,最后一次下单的订单id、下单时间,在 odps 中有 3 种方式可以实现:
CREATE TABLE IF NOT EXISTS orders
(
order_id STRING COMMENT '工单id'
,user_id BIGINT COMMENT '用户id'
,order_time DATETIME COMMENT '下单时间'
)
COMMENT '订单表'
PARTITIONED BY
(
ds STRING
)
LIFECYCLE 30
;
-- 窗口函数,每条数据都可以获取最大值和最小值
SELECT *
,FIRST_VALUE(order_id) OVER (PARTITION BY user_id ORDER BY order_time ) AS first_order_id
,FIRST_VALUE(order_time) OVER (PARTITION BY user_id ORDER BY order_time ) AS first_order_time
,LAST_VALUE(order_id) OVER (PARTITION BY user_id ORDER BY order_time ) AS last_order_id
,LAST_VALUE(order_time) OVER (PARTITION BY user_id ORDER BY order_time ) AS last_order_time
FROM order
WHERE ds = MAX_PT('order')
;
-- 聚合函数
SELECT user_id
,ARG_MIN(order_time,order_id) AS first_order_id
,MIN_BY(order_id,order_time) AS first_order_id2 -- MIN_BY 函数的字段顺序和 ARG_MIN 是相反的
,MIN(order_time) AS first_order_time
,ARG_MAX(order_time,order_id) AS last_order_id
,MAX_BY(order_id,order_time) AS last_order_id2 -- MAX_BY 函数的字段顺序和 ARG_MAX 是相反的
,MAX(order_time) AS last_order_time
FROM order
WHERE ds = MAX_PT('order')
GROUP BY user_id
;FROM_JSON(json_ext,"array<string>")-- NAMED_STRUCT 函数 VALUE 类型可以不是不同类型,但经过 TO_JSON 处理后,KEY 会全部转小写
TO_JSON(NAMED_STRUCT('type',type, 'data',data))
-- MAP 函数限制 VALUE 的类型必须是一样的,STRING 通用性最高,一般都用 STRING
TO_JSON(MAP('game_name',game_name))
-- JSON_OBJECT 可以保持 string、number、boolean 类型,但是不支持嵌套
JSON_OBJECT('a', 123,'b','hello')如果既想让 VALUE 具有不同的类型,KEY 也想用大小写,需要用 UDF 自定义实现:
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.odps.udf.UDF;
import com.aliyun.odps.udf.annotation.Resolve;
import org.apache.commons.lang.math.NumberUtils;
import java.util.Map;
import java.util.Objects;
/**
* 自定义 json 构造。
* TO_JSON + NAMED_STRUCT 会都改成小写
* TO_JSON + MAP 可以保持大小写,但是 MAP 限制必须是 MAP<STRING, STRING> 类型
* JSON_OBJECT 可以保持 string、number、boolean 类型,但是不支持嵌套
*/
@Resolve("MAP<STRING, STRING>->String")
public class ToJson extends UDF {
public String evaluate(Map<String, String> args) throws Exception {
if (Objects.isNull(args) || args.isEmpty()) {
return null;
}
JSONObject jsonObject = new JSONObject();
for (Map.Entry<String, String> entry : args.entrySet()) {
jsonObject.put(entry.getKey(), parseObjectOrArray(entry.getValue()));
}
return jsonObject.toJSONString();
}
private Object parseObjectOrArray(String string) {
try {
// 可以对不同类型的字段进行针对性类型转换
if (NumberUtils.isDigits(string)) {
return NumberUtils.createNumber(string);
}
Object parse = JSONObject.parse(string);
if (parse instanceof JSONObject) {
return parse;
} else if (parse instanceof JSONArray) {
return parse;
} else {
return string;
}
} catch (Exception e) {
return string;
}
}
}