MySQL第四天0319 日期函数,流程函数,多表连接查询~等值、非等值、自身连接,ANSL SQL~自然、using、on、外连接

本文详细介绍了SQL中日期时间函数的使用方法,包括NOW、CURDATE、CURTIME、TIMEDIFF、DATEDIFF等,以及如何进行日期时间的加减操作。同时,深入解析了流程函数如CASE、IF、IFNULL的应用场景,并提供了多表连接查询的基本写法和注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 日期函数
    • 1、NOW():返回服务器的当前日期和时间
    • 2、CURDATE():返回当前日期;
    • 3、CURTIME():返回当前时间,只包含时分秒
      • select now(),curdate(),curtime(),utc_date(),utc_time()
      • select now(),now()+10,now()+90
      • select curdate(),curdate()+0,curdate()+20,
      • date_add(curdate(), interval 10 day),
      • date_add(curdate(), interval 20 day)
      • select curtime(),curtime()+10
    • 4、TIMEDIFF(expr1, expr2):返回两个时间的时间差
      • select timediff('09:50:20','08:15:10')
    • 5、DATEDIFF(expr1, expr2):返回两个日期相差的【天数】
      • select datediff('2020-3-19','2020-02-17')
    • 6、DATE_ADD(date, INTERVAL expr unit) 给date增加一个间隔
      • 增加20年、月、日
        • select curdate(),date_add(curdate(), interval 20 year)
        • select curdate(),date_add(curdate(), interval 20 month)
        • select curdate(),date_add(curdate(), interval 20 day)
      • 增加20小时、分钟
        • select now(),date_add(now(), interval 20 hour)
        • select now(),date_add(now(), interval 20 minute)
      • 增加10年5个月
        • select now(),date_add(now(), interval '10-5' YEAR_MONTH)
      • 增加10小时20分钟5秒
        • select now(),date_add(now(), interval '10:20:5' HOUR_SECOND)
      • date_add()简写为+
        • select now(), now()+interval '10-5' YEAR_MONTH
        • select now(), now()+interval '10:20:5' HOUR_SECOND
    • 7、DATE_SUB(date, INTERVAL expr unit) 给date减去一个间隔
      • 减少20天
        • select curdate(),date_sub(curdate(), interval 20 day)
    • 8、提取日期时间的各个部分:
      • date() time()
      • year() month() day() quarter() week()
      • hour() minute() second() microsecond()
      • 也可以使用 EXTRACT(unit FROM date)
        • select now(),date(now()),time(now()),year(now())
        • select year(now()), day(now()), week(now()), extract(year from now())
        • select hiredate, year(hiredate), extract(year from hiredate) from emp
    • 9、dayofweek(date)、dayofmonth(date)、dayofyear(date)
      • select now(),dayofweek(now()),dayofmonth(now()),dayofyear(now())
    • 10、日期时间格式化函数:DATE_FORMAT(date,format)、TIME_FORMAT(time,format)
      • %Y:代表4位的年份
      • %y:代表2为的年份
      • %m:代表月,格式为(01……12)
      • %c:代表月,格式为(1……12)
      • %d:代表天数,格式为(00……31)
      • %e:代表天数,格式为(0……31)
      • %H:代表小时,格式为(00……23)
      • %h:代表小时,格式为(01……12)
      • %i:代表分钟,格式为(00……59)
      • %s:代表秒,格式为(00……59)
      • select now(), DATE_FORMAT(now(),'%Y/%m/%d---%H:%i:%s')
    • 11、补充函数:TIMESTAMPDIFF(type,开始时间,结束时间)
      • type取值:year、month、day、hour、minute、second、week、quarter
        • select timestampdiff(month,'20000101',now())
    • 12、补充函数:FORMAT(data,精度)
      • select sal,format(sal,2) from emp
  • 流程函数
    • 1、case
      • select sal,
      • case
        • when sal<1000 then 'low'
        • when sal>=1000 and sal<3000 then 'middle'
        • when sal>=3000 and sal<4000 then 'high'
        • else 'very high'
      • end
      • from emp
      •  
      • select sal,
      • case sal<1000
      • when true then 'low'
      • when false then 'high'
      • end
      • from emp
    • 2、if、ifnull
      • SELECT IF(1<2,2,3);
      • SELECT IF(1<2,'success','fail');
      • select ifnull(comm,0) from emp
    • 3、其他
      • 明文 ename
      • 秘文 md5(ename)
        • select ename, md5(ename) from emp
  • 多表连接查询
    • 基本写法
      • 笛卡尔积
        • 两个表所有行都发生连接
        • 连接条件不足
      • 等值连接
        • and
        • 多表
      • 限制歧义列
        • 查询工作地点在NEW YORK的员工编号,姓名,部门编号,工作地点
        • deptno是歧义列,因为emp表中有deptno,dept表中有deptno,到底哪个?
        • 需要明确指出哪个表的deptno,否则报错
      • 表的别名
        • emp e, emp m
      • 非等值连接
      • 自身连接
        • emp e, emp p 理解成类和对象
    • ANSI SQL
      • 交叉连接
        • cross join
      • 自然连接
        • natural join 对两个表之间相同名字和数据类型的列进行的等值连接
      • using 子句
        • select * from emp join dept using (deptno)
      • on子句
        • select * from emp join dept on(emp.deptno=dept.deptno)
      • 外部连接
        • left outer join
        • right outer join
``` #include <map> #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define lson rt << 1 #define rson rt << 1 | 1 using namespace std; const int A = 2e5 + 11; const int B = 1e6 + 11; const int mod = 1e9; const int inf = 0x3f3f3f3f; inline int read() { char c = getchar(); int x = 0, f = 1; for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1; for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48); return x * f; } bool flag; map <int, int> last; int sl[A], topl, sr[A], topr; struct tr { int l, r, lazy, w; } t[A << 2]; int n, k, d, ansl = 1, ansr = 1, a[A], ans; inline void pushup(int rt) { t[rt].w = min(t[lson].w, t[rson].w); } inline void calc(int rt, int x) { t[rt].lazy += x, t[rt].w += x; } inline void pushdown(int rt) { if (t[rt].lazy && t[rt].l < t[rt].r) { calc(lson, t[rt].lazy), calc(rson, t[rt].lazy); t[rt].lazy = 0; } } void build(int rt, int l, int r) { t[rt].l = l, t[rt].r = r, t[rt].lazy = 0, t[rt].w = 0; if (l == r) { t[rt].w = l; return; } int mid = (l + r) >> 1; build(lson, l, mid), build(rson, mid + 1, r); pushup(rt); } void insert(int rt, int l, int r, int k) { if (l <= t[rt].l && t[rt].r <= r) return calc(rt, k); pushdown(rt); int mid = (t[rt].l + t[rt].r) >> 1; if (l <= mid) insert(lson, l, r, k); if (r > mid) insert(rson, l, r, k); pushup(rt); } int work(int rt, int k) { if (t[rt].l == t[rt].r) return t[rt].l; pushdown(rt); if (t[lson].w <= k) return work(lson, k); else return work(rson, k); } void query(int rt, int l, int r, int k) { if (l <= t[rt].l && t[rt].r <= r) { if (t[rt].w <= k) flag = 1, ans = work(rt, k); return; } pushdown(rt); int mid = (t[rt].l + t[rt].r) >> 1; if (l <= mid && !flag) query(lson, l, r, k); if (r > mid && !flag) query(rson, l, r, k); } void del(int rt, int x) { if (x < t[rt].l || x > t[rt].r) return; pushdown(rt); if (t[rt].l == x && t[rt].r == x) { t[rt].w = 0; return; } del(lson, x), del(rson, x); pushup(rt); } int main() { n = read(), k = read(), d = read(); for (int i = 1; i <= n; i++) a[i] = read() + inf; if (d == 0) { for (int i = 1; i <= n; i++) { int l = i; while (a[i] == a[i + 1] && i < n) i++; if (ansr - ansl < i - l) ansl = l, ansr = i; } cout << ansl << ' ' << ansr << '\n'; return 0; } build(1, 1, n); //枚举右端点 for (int i = 1, L = 1; i <= n; i++) { int tmp = L; if (a[i] % d == a[i - 1] % d) L = max(L, last[a[i]] + 1); else L = i; last[a[i]] = i; while (tmp < L) del(1, tmp++); //递增栈 while (topl && sl[topl] >= L && a[sl[topl]] >= a[i]) { insert(1, max(L, sl[topl - 1] + 1), sl[topl], a[sl[topl]] / d); topl--; } insert(1, max(L, sl[topl] + 1), i, -a[i] / d); sl[++topl] = i; //递减栈 while (topr && sr[topr] >= L && a[sr[topr]] <= a[i]) { insert(1, max(L, sr[topr - 1] +1), sr[topr], -a[sr[topr]] / d); topr--; } insert(1, max(L, sr[topr] + 1), i, a[i] / d); sr[++topr] = i; flag = 0, ans = 0; query(1, L, i, k + i); //思路中的式子 if (ansr - ansl < i - ans) ansl = ans, ansr = i; } cout << ansl << " " << ansr << '\n'; return 0; }```请结合题目要求给这段代码添加注释。题目要求:找一个最长的子区间使得该子区间加入至 k 个数以后,排序后是一个公差为 d 的等差数列。 输出这个子区间的左端点l和右端点r, 个解输出 l 最小的。
最新发布
03-09
<think>好的,我现在需要帮用户给一段C++代码添加注释,结合题目要求。题目是找一个最长的子区间,使得加入至k个数后能排序成公差为d的等差数列。输出左端点最小的解。 首先,我得理解代码的结构和逻辑。用户提供的代码看起来是解决这个问题的,但需要详细注释。我需要先通读代码,了解各部分的功能,然后结合题目要求添加注释。 代码开头包含了一些头文件,比如map、cmath等,可能用于数据结构和数学运算。然后定义了一些常量和宏,比如lson和rson,可能用于线段树的左右子节点。接着声明了全局变量,比如last(可能是记录元素最后出现位置的map)、两个栈sl和sr(可能用于单调栈),线段树结构体tr,还有一些变量如ansl、ansr等。 主函数里,首先处理d=0的情况,这时候等差数列公差为0,直接找最长的连续相同元素区间。然后处理d≠0的情况,构建线段树,枚举右端点i,维护左端点L,处理可能的重复元素,使用单调栈维护最大最小值,通过线段树进行区间修改和查询,找到满足条件的最长区间。 接下来需要为每个关键部分添加注释,解释其作用。例如,线段树的build函数用于构建结构,insert进行区间更新,work和query用于查询满足条件的位置。主循环中的单调栈处理最大最小值,更新线段树中的信息,最后查询可能的左端点。 需要注意注释要清晰,说明每个变量和函数的作用,尤其是与题目要求相关的部分,比如如何利用线段树维护条件,单调栈如何帮助计算最大最小值的变化,以及如何通过查询找到符合条件的左端点。 同时,要结合题目中的数学条件,例如,当d≠0时,子区间内的元素必须满足模d同余,且调整后的极值差不超过k*d。这些条件可能在代码中通过取模运算和线段树的更新来实现,需要在注释中说明。 可能遇到的难点包括理解线段树在此处的具体应用,以及单调栈如何维护最大最小值的信息。需要确保注释能准确反映这些逻辑,帮助读者理解代码如何解决问题。 最后,要确保注释用中文书写,符合用户要求,并且结构清晰,分步骤解释代码各部分的功能,尤其是与算法关键步骤相关的部分。</think>```cpp #include <map> #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define lson rt << 1 // 线段树左子节点宏定义 #define rson rt << 1 | 1 // 线段树右子节点宏定义 using namespace std; const int A = 2e5 + 11; // 数组大小常量 const int B = 1e6 + 11; const int mod = 1e9; const int inf = 0x3f3f3f3f; // 无穷大常量 // 快速读入优化函数 inline int read() { char c = getchar(); int x = 0, f = 1; for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1; for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48); return x * f; } bool flag; // 查询标记 map <int, int> last; // 记录每个数值最后一次出现的位置 int sl[A], topl; // 左侧单调栈(维护最小值)及其栈顶指针 int sr[A], topr; // 右侧单调栈(维护最大值)及其栈顶指针 // 线段树节点结构体 struct tr { int l, r, lazy, w; } t[A << 2]; int n, k, d; // 题目输入参数 int ansl = 1, ansr = 1; // 答案区间 int a[A], ans; // 原始数组及临时答案 // 线段树上传操作(取最小值) inline void pushup(int rt) { t[rt].w = min(t[lson].w, t[rson].w); } // 线段树区间增加值操作 inline void calc(int rt, int x) { t[rt].lazy += x, t[rt].w += x; } // 线段树下传延迟标记 inline void pushdown(int rt) { if (t[rt].lazy && t[rt].l < t[rt].r) { calc(lson, t[rt].lazy), calc(rson, t[rt].lazy); t[rt].lazy = 0; } } // 线段树构建函数(初始值为下标) void build(int rt, int l, int r) { t[rt].l = l, t[rt].r = r, t[rt].lazy = 0, t[rt].w = 0; if (l == r) { t[rt].w = l; return; } // 叶子节点初始值为下标 int mid = (l + r) >> 1; build(lson, l, mid), build(rson, mid + 1, r); pushup(rt); } // 线段树区间插入操作(增加k值) void insert(int rt, int l, int r, int k) { if (l <= t[rt].l && t[rt].r <= r) return calc(rt, k); pushdown(rt); int mid = (t[rt].l + t[rt].r) >> 1; if (l <= mid) insert(lson, l, r, k); if (r > mid) insert(rson, l, r, k); pushup(rt); } // 在线段树中查找第一个<=k的位置(关键查询) int work(int rt, int k) { if (t[rt].l == t[rt].r) return t[rt].l; pushdown(rt); if (t[lson].w <= k) return work(lson, k); else return work(rson, k); } // 区间查询函数(寻找满足条件的最左端点) void query(int rt, int l, int r, int k) { if (l <= t[rt].l && t[rt].r <= r) { if (t[rt].w <= k) flag = 1, ans = work(rt, k); return; } pushdown(rt); int mid = (t[rt].l + t[rt].r) >> 1; if (l <= mid && !flag) query(lson, l, r, k); if (r > mid && !flag) query(rson, l, r, k); } // 线段树单点删除操作(维护滑动窗口) void del(int rt, int x) { if (x < t[rt].l || x > t[rt].r) return; pushdown(rt); if (t[rt].l == x && t[rt].r == x) { t[rt].w = 0; return; } del(lson, x), del(rson, x); pushup(rt); } int main() { n = read(), k = read(), d = read(); for (int i = 1; i <= n; i++) a[i] = read() + inf; // 防止负数取模问题 // 处理d=0的特殊情况(所有元素必须相同) if (d == 0) { for (int i = 1; i <= n; i++) { int l = i; while (a[i] == a[i + 1] && i < n) i++; if (ansr - ansl < i - l) ansl = l, ansr = i; } cout << ansl << ' ' << ansr << '\n'; return 0; } build(1, 1, n); // 初始化线段树 // 枚举右端点i,滑动窗口维护左端点L for (int i = 1, L = 1; i <= n; i++) { // 维护相同余数区间(必须同余才能构成等差数列) int tmp = L; if (a[i] % d == a[i - 1] % d) L = max(L, last[a[i]] + 1); else L = i; last[a[i]] = i; // 更新最后出现位置 // 删除滑动窗口外元素对线段树的影响 while (tmp < L) del(1, tmp++); /* 维护两个单调栈: sl维护最小值栈,用于计算最小值的贡献 sr维护最大值栈,用于计算最大值的贡献 公式推导:所需添加元素数 = (max - min)/d - (r - l) <= k 转换为:max/d - min/d <= k + (r - l) => (max/d - min/d) - (r - l) <= k 通过线段树维护该值 */ // 处理左侧单调栈(最小值栈) while (topl && sl[topl] >= L && a[sl[topl]] >= a[i]) { insert(1, max(L, sl[topl - 1] + 1), sl[topl], a[sl[topl]] / d); topl--; } insert(1, max(L, sl[topl] + 1), i, -a[i] / d); sl[++topl] = i; // 处理右侧单调栈(最大值栈) while (topr && sr[topr] >= L && a[sr[topr]] <= a[i]) { insert(1, max(L, sr[topr - 1] +1), sr[topr], -a[sr[topr]] / d); topr--; } insert(1, max(L, sr[topr] + 1), i, a[i] / d); sr[++topr] = i; // 查询满足条件的最左端点 flag = 0, ans = 0; query(1, L, i, k + i); // 查询满足条件的最小左端点 if (ansr - ansl < i - ans) ansl = ans, ansr = i; } cout << ansl << " " << ansr << '\n'; return 0; } ``` ### 核心算法注释说明 1. **特殊处理d=0** 当$d=0$时,等差数列退化为所有元素相同。此时直接寻找最长连续相同元素区间。 2. **滑动窗口维护同余条件** 通过`last`数组维护数值最后出现位置,确保区间内所有元素满足$a_i \equiv a_j \ (\text{mod}\ d)$。 3. **单调栈维护极值** - 左侧栈`sl`维护最小值序列,保证栈内元素递增 - 右侧栈`sr`维护最大值序列,保证栈内元素递减 - 每次入栈时计算极值变化对公式$(max/d - min/d) - (r-l)$的影响 4. **线段树核心作用** 维护达式$\text{value} = (\frac{\text{max}}{d} - \frac{\text{min}}{d}) - (i - l)$,通过区间修改和查询,找到满足$\text{value} \leq k$的最长区间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值