SQL_STUDY:14.SQL Date 函数和 SQL NULL 值

这篇博客介绍了SQL中的日期处理,包括MySQL和SQL Server的重要日期函数,如NOW()、GETDATE()、DATE_ADD()等。同时,详细阐述了SQL NULL值的概念,强调了NULL与0的区别,并讲解了如何使用IS NULL、IS NOT NULL操作符来处理NULL值。此外,还介绍了替代函数ISNULL()、NVL()、IFNULL()和COALESCE()在处理NULL时的作用。

摘要:

  1. SQL Date 函数
  2. SQL NULL 值的 使用 IS NULL 和 IS NOT NULL
  3. isnull() 函数 可以用来进行数字和null 的加法 等。

SQL 日期

当我们处理日期时,最难的任务恐怕是确保所插入的日期的格式,与数据库中日期列的格式相匹配。

只要数据包含的只是日期部分,运行查询就不会出问题。但是,如果涉及时间,情况就有点复杂了。

在讨论日期查询的复杂性之前,我们先来看看最重要的内建日期处理函数。

MySQL Date 函数
下面的表格列出了 MySQL 中最重要的内建日期函数:

函数 描述
NOW() 返回当前的日期和时间
CURDATE() 返回当前的日期
CURTIME() 返回当前的时间
DATE() 提取日期或日期/时间表达式的日期部分
EXTRACT() 返回日期/时间按的单独部分
DATE_ADD() 给日期添加指定的时间间隔
DATE_SUB() 从日期减去指定的时间间隔
DATEDIFF() 返回两个日期之间的天数
DATE_FORMAT() 用不同的格式显示日期/时间


SQL Server Date 函数
下面的表格列出了 SQL Server 中最重要的内建日期函数:

函数 描述
GETDATE() 返回当前日期和时间
DATEPART() 返回日期/时间的单独部分
DATEADD() 在日期中添加或减去指定的时间间隔
DATEDIFF() 返回两个日期之间的时间
CONVERT() 用不同的格式显示日期/时间


SQL Date 数据类型
MySQL 使用下列数据类型在数据库中存储日期或日期/时间值:

DATE - 格式 YYYY-MM-DD
DATETIME - 格式: YYYY-MM-DD HH:MM:SS
TIMESTAMP - 格式: YYYY-MM-DD HH:MM:SS
YEAR - 格式 YYYY 或 YY
SQL Server 使用下列数据类型在数据库中存储日期或日期/时间值:

DATE - 格式 YYYY-MM-DD
DATETIME - 格式: YYYY-MM-DD HH:MM:SS
SMALLDATETIME - 格式: YYYY-MM-DD HH:MM:SS
TIMESTAMP - 格式: 唯一的数字

SQL 日期处理
如果不涉及时间部分,那么我们可以轻松地比较两个日期!

假设我们有下面这个 “Orders” 表:

OrderId ProductName OrderDate
1 computer 2008-12-26
2 printer 2008-12-26
3 electrograph 2008-11-12
4 telephone 2008-10-19
现在,我们希望从上表中选取 OrderDate 为 “2008-12-26” 的记录。

我们使用如下 SELECT 语句:

SELECT * FROM Orders WHERE OrderDate=‘2008-12-26’
结果集:

OrderId ProductName OrderDate
1 computer 2008-12-26
3 electrograph 2008-12-26
现在假设 “Orders” 类似这样(请注意 “OrderDate” 列中的时间部分):

OrderId ProductName OrderDate
1 computer 2008-12-26 16:23:55
2 printer 2008-12-26 10:45:26
3 electrograph 2008-11-12 14:12:08
4 telephone 2008-10-19 12:56:10
如果我们使用上面的 SELECT 语句:

SELECT * FROM Orders WHERE OrderDate=‘2008-12-26’
那么我们得不到结果。这是由于该查询不含有时间部分的日期。

提示:如果您希望使查询简单且更易维护,那么请不要在日期中使用时间部分!


SQL NULL 值

NULL 值是遗漏的未知数据。

默认地,表的列可以存放 NULL 值。

本章讲解 IS NULL 和 IS NOT NULL 操作符。

SQL NULL 值

如果表中的某个列是可选的,那么我们可以在不向该列添加值的情况下插入新记录或更新已有的记录。这意味着该字段将以 NULL 值保存。

NULL 值的处理方式与其他值不同。

NULL 用作未知的或不适用的值的占位符。

注释:无法比较 NULL 和 0;它们是不等价的。

SQL 的 NULL 值处理

请看下面的 “Persons” 表:

Id LastName FirstName Address City
1 Adams John London
2 Bush George Fifth Avenue New York
3 Carter Thomas Beijing
假如 “Persons” 表中的 “Address” 列是可选的。这意味着如果在 “Address” 列插入一条不带值的记录,“Address” 列会使用 NULL 值保存。

那么我们如何测试 NULL 值呢?

无法使用比较运算符来测试 NULL 值,比如 =, <, 或者 <>。

我们必须使用 IS NULL 和 IS NOT NULL 操作符。


SQL IS NULL

我们如何仅仅选取在 “Address” 列中带有 NULL 值的记录呢?

我们必须使用 IS NULL 操作符:

SELECT LastName,FirstName,Address FROM Persons
WHERE Address IS NULL

结果集:

LastName FirstName Address
Adams John
Carter Thomas
提示:请始终使用 IS NULL 来查找 NULL 值。


SQL IS NOT NULL

我们如何选取在 “Address” 列中不带有 NULL 值的记录呢?

我们必须使用 IS NOT NULL 操作符:

SELECT LastName,FirstName,Address FROM Persons
WHERE Address IS NOT NULL

结果集:

LastName FirstName Address
Bush George Fifth Avenue
在下一节中,我们了解 ISNULL()、NVL()、IFNULL() 和 COALESCE() 函数。


SQL NULL 函数

SQL ISNULL()、NVL()、IFNULL() 和 COALESCE() 函数

请看下面的 “Products” 表:

P_Id ProductName UnitPrice UnitsInStock UnitsOnOrder
1 computer 699 25 15
2 printer 365 36
3 telephone 280 159 57
假如 “UnitsOnOrder” 是可选的,而且可以包含 NULL 值。

我们使用如下 SELECT 语句:

SELECT ProductName,UnitPrice*(UnitsInStock+UnitsOnOrder)
FROM Products

在上面的例子中,如果有 “UnitsOnOrder” 值是 NULL,那么结果是 NULL。

微软的 ISNULL() 函数用于规定如何处理 NULL 值。

NVL(), IFNULL() 和 COALESCE() 函数也可以达到相同的结果。

在这里,我们希望 NULL 值为 0。

下面,如果 “UnitsOnOrder” 是 NULL,则不利于计算,因此如果值是 NULL 则 ISNULL() 返回 0。

SQL Server / MS Access

SELECT ProductName,UnitPrice*(UnitsInStock+ISNULL(UnitsOnOrder,0))
FROM Products

Oracle
Oracle 没有 ISNULL() 函数。不过,我们可以使用 NVL() 函数达到相同的结果:

SELECT ProductName,UnitPrice*(UnitsInStock+NVL(UnitsOnOrder,0))
FROM Products

MySQL
MySQL 也拥有类似 ISNULL() 的函数。不过它的工作方式与微软的 ISNULL() 函数有点不同。

在 MySQL 中,我们可以使用 IFNULL() 函数,就像这样:

SELECT ProductName,UnitPrice*(UnitsInStock+IFNULL(UnitsOnOrder,0))
FROM Products

或者我们可以使用 COALESCE() 函数,就像这样:

SELECT ProductName,UnitPrice*(UnitsInStock+COALESCE(UnitsOnOrder,0))
FROM Products
我知道sql中各个关键字的含义,请帮我梳理下列sql想要表达的修改逻辑 UPDATE i_tigermed_po_study_unitbase_progress SET cumulative_unit_count = ( SELECT COALESCE(SUM(COALESCE(actual_cnt, forecast_cnt)), 0) FROM ( SELECT t2.data_month, MAX(CASE WHEN t2.data_type = 'actual' AND (i_tigermed_po_study_unitbase_progress.data_type = 'forecast' OR t2.data_month <![CDATA[<=]]> i_tigermed_po_study_unitbase_progress.data_month) THEN t2.period_unit_count END) AS actual_cnt, MAX(CASE WHEN t2.data_type = 'forecast' THEN t2.period_unit_count END) AS forecast_cnt FROM i_tigermed_po_study_unitbase_progress t2 INNER JOIN ( SELECT t31.data_month, t31.data_type, MAX(t31.view_month) AS max_view_month FROM i_tigermed_po_study_unitbase_progress t31 WHERE t31.study_unitbase_id = i_tigermed_po_study_unitbase_progress.study_unitbase_id AND t31.unitbase_task_id = i_tigermed_po_study_unitbase_progress.unitbase_task_id AND t31.view_month <![CDATA[<=]]> i_tigermed_po_study_unitbase_progress.view_month AND t31.is_deleted = '0' GROUP BY t31.data_month, t31.data_type ) t3 ON t2.data_month = t3.data_month AND t2.data_type = t3.data_type AND t2.view_month = t3.max_view_month WHERE t2.study_unitbase_id = i_tigermed_po_study_unitbase_progress.study_unitbase_id AND t2.unitbase_task_id = i_tigermed_po_study_unitbase_progress.unitbase_task_id AND (t2.data_type = i_tigermed_po_study_unitbase_progress.data_type OR i_tigermed_po_study_unitbase_progress.data_type = 'forecast') AND t2.data_month <![CDATA[<=]]> i_tigermed_po_study_unitbase_progress.data_month AND t2.is_deleted = '0' GROUP BY t2.data_month ) tt ) WHERE study_unitbase_id = #{studyUnitbaseId}::INT8 AND view_mon
03-29
WITH consecutive_sessions AS ( -- First, get all study sessions with row numbers to identify consecutive sessions SELECT ss.student_id, ss.subject, ss.session_date, ss.hours_studied, ROW_NUMBER() OVER (PARTITION BY ss.student_id ORDER BY ss.session_date) as session_order FROM study_sessions ss ), session_groups AS ( -- Group consecutive sessions by checking date gaps SELECT cs1.*, -- Check if there's a gap > 2 days from previous session CASE WHEN LAG(session_date) OVER (PARTITION BY student_id ORDER BY session_date) IS NULL THEN 1 WHEN DATEDIFF(session_date, LAG(session_date) OVER (PARTITION BY student_id ORDER BY session_date)) <= 2 THEN 0 ELSE 1 END as is_new_group FROM consecutive_sessions cs1 ), grouped_sessions AS ( -- Create group numbers for consecutive session sequences SELECT *, SUM(is_new_group) OVER (PARTITION BY student_id ORDER BY session_date) as group_id FROM session_groups ), pattern_analysis AS ( -- For each group of consecutive sessions, analyze the pattern SELECT student_id, group_id, COUNT(DISTINCT subject) as unique_subjects, COUNT(*) as total_sessions, SUM(hours_studied) as total_hours, -- Create the subject sequence string to check for repeating patterns GROUP_CONCAT(subject ORDER BY session_date SEPARATOR '|') as subject_sequence FROM grouped_sessions GROUP BY student_id, group_id HAVING COUNT(*) >= 6 -- At least 6 sessions for 2 complete cycles of 3 subjects AND COUNT(DISTINCT subject) >= 3 -- At least 3 different subjects ), valid_patterns AS ( -- Check if the pattern actually repeats for at least 2 complete cycles SELECT student_id, group_id, unique_subjects as cycle_length, total_sessions, total_hours, subject_sequence, -- Check if we have at least 2 complete cycles CASE WHEN total_sessions >= (unique_subjects * 2) THEN 1 ELSE 0 END as has_complete_cycles FROM pattern_analysis ), cycle_validation AS ( -- Validate that the pattern actually repeats correctly SELECT gs.student_id, gs.group_id, vp.cycle_length, vp.total_hours, -- Check if the subject sequence repeats correctly COUNT(*) as session_count, -- Get the first cycle pattern GROUP_CONCAT( CASE WHEN gs.session_order <= vp.cycle_length THEN gs.subject ELSE NULL END ORDER BY gs.session_date SEPARATOR '|' ) as first_cycle, -- Check if subsequent sessions follow the same pattern COUNT(CASE WHEN gs.session_order > vp.cycle_length AND gs.subject = ( SELECT subject FROM grouped_sessions gs2 WHERE gs2.student_id = gs.student_id AND gs2.group_id = gs.group_id AND gs2.session_order = ((gs.session_order - 1) % vp.cycle_length) + 1 ) THEN 1 ELSE NULL END) as matching_pattern_count FROM grouped_sessions gs JOIN valid_patterns vp ON gs.student_id = vp.student_id AND gs.group_id = vp.group_id WHERE vp.has_complete_cycles = 1 GROUP BY gs.student_id, gs.group_id, vp.cycle_length, vp.total_hours HAVING session_count >= (cycle_length * 2) AND matching_pattern_count = (session_count - cycle_length) -- All sessions after first cycle match pattern ) -- Final result with student information SELECT s.student_id, s.student_name, s.major, cv.cycle_length, cv.total_hours as total_study_hours FROM cycle_validation cv JOIN students s ON cv.student_id = s.student_id ORDER BY cv.cycle_length DESC, cv.total_hours DESC
最新发布
11-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值