按月份统计人员每天是否登录过系统,查询出来格式如下

本文介绍了一种统计员工每月登录系统情况的方法,通过SQL查询实现了按天展示每位员工的登录状态,并计算出勤天数。

有两个表:人员表T1,登录信息表T2
T1有两个栏位:EMPID(人员ID),EMPNAME(人员姓名)
T2有两个栏位:EMPID(人员ID),LOGTIME(登录时间)
按月份统计人员每天是否登录过系统,查询出来格式如下:
姓名 1,2,3,4……一直到31号(选择的月份有几天就是多少天),最后再加这个人当月的出勤,只要当天登录过就是出勤了!
详细格式请看下面的图片:
http://60.216.13.200/123.jpg
谢谢啊!!!

 

 

--
----------------------------------- 

--
Author : Luoyoumou
--
Comment: 三月红梨
--
Date : 2009-11-04 06:37:17
--
-------------------------------------
create table t1(empid varchar ( 10 ), empname varchar ( 20 ))
insert into t1(empid, empname)
select
' 0001 ' , ' 张三 ' union all select
' 0002 ' , ' 李四 ' union all select
' 0003 ' , ' 王五 ' union all select
' 0004 ' , ' 赵六 ' ;

create table t2(empid varchar ( 10 ), logtime datetime )

insert into t2(empid, logtime)
select
' 0001 ' , ' 2009-09-05 ' union all select
' 0001 ' , ' 2009-01-11 ' union all select
' 0001 ' , ' 2009-01-14 ' union all select
' 0001 ' , ' 2009-01-23 ' union all select
' 0001 ' , ' 2009-01-01 ' union all select
' 0001 ' , ' 2009-02-05 ' union all select
' 0001 ' , ' 2009-06-04 ' union all select
' 0001 ' , ' 2009-07-11 ' union all select
' 0001 ' , ' 2009-07-11 ' union all select
' 0001 ' , ' 2009-05-11 ' union all select
' 0001 ' , ' 2009-03-11 ' union all select
' 0001 ' , ' 2009-03-11 ' union all select
' 0001 ' , ' 2009-03-11 ' union all select
' 0001 ' , ' 2009-02-02 ' union all select
' 0001 ' , ' 2009-02-03 ' union all select
' 0001 ' , ' 2009-02-04 ' union all select
' 0001 ' , ' 2009-02-06 ' union all select
' 0001 ' , ' 2009-03-11 ' union all select
' 0001 ' , ' 2009-08-02 ' union all select
' 0001 ' , ' 2009-08-03 ' union all select
' 0001 ' , ' 2009-08-04 ' union all select
' 0001 ' , ' 2009-09-16 ' union all select
' 0001 ' , ' 2009-09-02 ' union all select
' 0001 ' , ' 2009-09-03 ' union all select
' 0001 ' , ' 2009-09-04 ' union all select
' 0001 ' , ' 2009-09-16 ' union all select
' 0002 ' , ' 2009-01-11 ' union all select
' 0002 ' , ' 2009-01-14 ' union all select
' 0002 ' , ' 2009-01-23 ' union all select
' 0002 ' , ' 2009-01-01 ' union all select
' 0002 ' , ' 2009-02-05 ' union all select
' 0002 ' , ' 2009-06-04 ' union all select
' 0002 ' , ' 2009-07-11 ' union all select
' 0002 ' , ' 2009-07-11 ' union all select
' 0002 ' , ' 2009-05-11 ' union all select
' 0002 ' , ' 2009-03-11 ' union all select
' 0002 ' , ' 2009-03-11 ' union all select
' 0002 ' , ' 2009-03-11 ' union all select
' 0002 ' , ' 2009-02-02 ' union all select
' 0002 ' , ' 2009-02-03 ' union all select
' 0002 ' , ' 2009-02-04 ' union all select
' 0002 ' , ' 2009-02-06 ' union all select
' 0002 ' , ' 2009-03-11 ' union all select
' 0002 ' , ' 2009-08-02 ' union all select
' 0002 ' , ' 2009-08-03 ' union all select
' 0002 ' , ' 2009-08-04 ' union all select
' 0002 ' , ' 2009-09-16 ' union all select
' 0002 ' , ' 2009-09-02 ' union all select
' 0002 ' , ' 2009-09-03 ' union all select
' 0002 ' , ' 2009-09-04 ' union all select
' 0002 ' , ' 2009-09-16 ' union all select
' 0003 ' , ' 2009-01-11 ' union all select
' 0003 ' , ' 2009-01-14 ' union all select
' 0003 ' , ' 2009-01-23 ' union all select
' 0003 ' , ' 2009-01-01 ' union all select
' 0003 ' , ' 2009-02-05 ' union all select
' 0003 ' , ' 2009-06-04 ' union all select
' 0003 ' , ' 2009-07-11 ' union all select
' 0003 ' , ' 2009-07-11 ' union all select
' 0003 ' , ' 2009-05-11 ' union all select
' 0003 ' , ' 2009-03-11 ' union all select
' 0003 ' , ' 2009-03-11 ' union all select
' 0003 ' , ' 2009-03-11 ' union all select
' 0003 ' , ' 2009-02-02 ' union all select
' 0003 ' , ' 2009-02-03 ' union all select
' 0003 ' , ' 2009-02-04 ' union all select
' 0003 ' , ' 2009-02-06 ' union all select
' 0003 ' , ' 2009-03-11 ' union all select
' 0003 ' , ' 2009-08-02 ' union all select
' 0003 ' , ' 2009-08-03 ' union all select
' 0003 ' , ' 2009-08-04 ' union all select
' 0003 ' , ' 2009-09-16 ' union all select
' 0003 ' , ' 2009-09-02 ' union all select
' 0003 ' , ' 2009-09-03 ' union all select
' 0003 ' , ' 2009-09-04 ' union all select
' 0003 ' , ' 2009-09-16 ' ;
-- ------------------------------------------

-- --备注: ∨:正常上班
--
∥:加班(周六、周日在上班)
--
○:休息

 

 

 

 

SET
 ANSI_NULLS 
ON

GO
SET QUOTED_IDENTIFIER ON
GO

ALTER procedure [ dbo ] . [ test_proc ] @year_month varchar ( 6 ) = null
/*
exec test_proc '200909'
*/
as
begin

declare @maxdays int , @countdays int ;
declare @SQL varchar ( max );

set @SQL = ' SELECT t1.empid, t1.empname, ' ;

set @countdays = 1 ;

-- 如果输入参数为空,则取当前年、月的考勤记录情况
if ( isnull ( @year_month , '' ) = '' )
SET @year_month = CONVERT ( varchar ( 6 ), getdate (), 112 );

-- 取本月最后一天
select @maxdays = day ( dateadd ( month , 1 , convert ( datetime , @year_month + ' 01 ' )) - 1 );

while ( @countdays <= @maxdays )
begin
SET @SQL = @SQL + ' [ ' + CONVERT ( VARCHAR ( 2 ), @countdays ) + ' ]=(CASE WHEN SUM(CASE WHEN day(t2.logtime)= ' + CONVERT ( VARCHAR ( 2 ), @countdays ) + ' then 1 else 0 end)>0 and DatePart(w, ''' + @year_month + '' +right ( ' 0 ' + convert ( varchar ( 2 ), @countdays ), 2 ) + ''' ) not in (1,7) THEN '' ''
WHEN SUM(CASE WHEN day(t2.logtime)=
' + CONVERT ( VARCHAR ( 2 ), @countdays ) + ' then 1 else 0 end)>0 and DatePart(w, ''' + @year_month + '' +right ( ' 0 ' + convert ( varchar ( 2 ), @countdays ), 2 ) + ''' ) in (1,7) THEN '' '' ELSE '' '' END), '
SET @countdays = @countdays + 1 ;
end

set @sql = substring ( @sql , 1 , len ( @sql ) - 2 );
set @sql = @sql + ' from t1 left join t2 on t1.empid=t2.empid and convert(varchar(6),t2.logtime,112)= ''' + @year_month + ''' '
set @sql = @sql + ' group by t1.empid, t1.empname, convert(varchar(6),t2.logtime,112) '
print ( @sql );
exec ( @SQL );

end

GO

SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
-- -------------------------------------------------------------------------------------

exec test_proc ' 200909 '

-- -------------------------------------------------------------------------------------------------- empid empname 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 0001 张三 ∨ ○ ○ ○ ∥ ○ ∨ ∨ ∨ ∨ ∨ ○ ○ ∨ ∨ ○ ∨ ∨ ○ ○ ∨ ∨ ∨ ∨ ∨ ○ ○ ∨ ∨ ∨ 0002 李四 ∨ ○ ○ ○ ○ ○ ∨ ∨ ∨ ∨ ∨ ○ ○ ∨ ∨ ○ ∨ ∨ ○ ○ ∨ ∨ ∨ ∨ ∨ ○ ○ ∨ ∨ ∨ 0003 王五 ∨ ○ ○ ○ ○ ○ ∨ ∨ ∨ ∨ ∨ ○ ○ ∨ ∨ ○ ∨ ∨ ○ ○ ∨ ∨ ∨ ∨ ∨ ○ ○ ∨ ∨ ∨ 0004 赵六 ∨ ∨ ∨ ∨ ○ ○ ∨ ∨ ∨ ∨ ∨ ○ ○ ∨ ∨ ∨ ∨ ∨ ○ ○ ∨ ∨ ∨ ∨ ∨ ○ ○ ∨ ∨ ∨

                
<think>嗯,用户的问题是关于如何用SQL月份汇总查询结果,涉及到数据分组和统计函数。首先,我需要回忆一下不同数据库系统中处理日期和时间的函数,因为用户提到的引用涉及了SQL Server、MySQL、PostgreSQL、Oracle和Excel,可能用户需要的是一个通用的方法,或者是针对特定数据库的解决方案。 用户提供的引用中有几个例子:比如引用1提到SQL Server中使用DATENAME函数拼接年月,引用2是MySQL使用LEFT函数截取日期前7位,引用3是PostgreSQL的日期处理,引用4是Excel中的GROUP BY多列,引用5是Oracle的to_date函数。这说明不同的数据库系统有不同的日期处理方式,用户可能需要跨数据库的解决方案,或者需要针对某个特定的数据库来回答。 首先,我需要确定用户使用的是哪种数据库,但用户没有明确说明,所以可能需要给出几种常见数据库的示例,比如MySQLSQL Server、Oracle和PostgreSQL。同时,用户的问题是关于按月份分组统计,所以核心步骤应该是提取日期中的年份和月份,然后按照这个分组,使用聚合函数统计。 接下来,要确保日期字段的格式是正确的,比如是否是日期类型。如果存储的是字符串,可能需要转换,或者使用字符串函数截取。比如在MySQL中,LEFT(create_date,7)可以获取'YYYY-MM',但前提是create_date格式是'YYYY-MM-DD'。如果是日期类型,可以使用DATE_FORMAT函数。 另外,用户提供的引用中有使用CASE WHEN进行条件统计,比如引用2中的SUM(CASE WHEN isday = 1 THEN 1 ELSE 0 END),这可能用户还需要在按月份分组的同时,进行条件统计,比如每个月的不同状态的数据量。所以可能需要包含这种条件聚合的例子。 然后,我需要考虑不同的数据库函数的差异,比如: - MySQLDATE_FORMAT(date_column, '%Y-%m') 或者 LEFT(date_column,7) - SQL Server:DATENAME(year, date_column) + '-' + DATENAME(month, date_column),但月份可能需要补零,因为DATENAME(month)返回的是月份的名称或数字,比如如果是数字,1月会是1,这样拼接成'2022-1',而不是'2022-01',所以可能需要使用RIGHT('0' + DATENAME(month, date_column), 2)来补零,或者使用CONVERT配合格式。 - Oracle:TO_CHAR(date_column, 'YYYY-MM') - PostgreSQL:TO_CHAR(date_column, 'YYYY-MM') 同时,还要注意分组时是否需要按照格式化后的字符串分组,比如GROUP BY TO_CHAR(date_column, 'YYYY-MM'),或者使用表达式。 另外,用户可能还需要处理日期范围,比如只统计某一年的数据,这时候需要在WHERE子句中加入条件,比如引用5中的WHERE sale_time >= to_date('2014-01-01', 'YYYY-MM-DD')。 还需要考虑性能问题,比如在MySQL中使用LEFT函数可能无法利用索引,而使用DATE_FORMAT可能也会影响性能,但用户的问题主要是如何实现,可能暂时不需要深入优化。 总结步骤应该是: 1. 提取日期中的年份和月份格式化为'YYYY-MM'。 2. 使用GROUP BY按照这个格式化后的字段分组。 3. 使用聚合函数如SUM、COUNT等进行统计。 4. 可选:添加WHERE条件限制日期范围。 5. 可选:使用条件聚合统计不同情况的数据。 现在需要将这些步骤用不同数据库的语法写出来,并给出示例。同时,根据用户提供的引用中的例子,可能需要引用这些方法,比如引用1中的DATENAME,引用2中的LEFT函数,引用5中的to_date。 还需要注意,在SQL Server中,DATENAME返回的是字符串,但月份如果是数字的话,比如1月返回'1',这样拼接会是'2022-1',而不是'2022-01',所以需要处理补零的问题,比如使用RIGHT('0' + DATENAME(month, date_column), 2),但DATENAME返回的月份如果是英文名称,比如'January',那这种方法就不行,所以可能需要使用MONTH函数获取月份的数字,然后格式化。例如: SELECT CONVERT(varchar, DATEPART(year, a.upload_time)) + '-' + RIGHT('0' + CONVERT(varchar, DATEPART(month, a.upload_time)), 2) 这可能更可靠。 在MySQL中,DATE_FORMAT(date_column, '%Y-%m')会自动补零,所以更简单。 在Oracle中,TO_CHAR(date_column, 'YYYY-MM')同样会补零。 PostgreSQL类似。 所以可能需要指出不同数据库的正确方法,并提醒用户注意月份补零的问题,以确保分组正确。 另外,用户的问题是关于按月份汇总,可能需要统计每个月的记录数,或者某数值字段的总和,比如销售额,所以示例中应该包括COUNT(*), SUM(sales)等。 最后,生成相关问题,可能需要围绕日期处理的其他方面,比如按周、季度统计,处理跨年数据,或者性能优化等。</think>### 分步解答 #### 核心步骤 1. **提取年月**:将日期字段转换为`YYYY-MM`格式的字符串 2. **分组聚合**:按格式化后的年月字段分组,使用统计函数(如`COUNT`, `SUM`) 3. **筛选范围**(可选):通过`WHERE`限定统计时间范围 #### 不同数据库实现方法 --- ##### **1. MySQL** ```sql SELECT DATE_FORMAT(create_date, '%Y-%m') AS year_month, COUNT(*) AS total_records, SUM(sales) AS total_sales FROM orders WHERE create_date BETWEEN '2023-01-01' AND '2023-12-31' GROUP BY year_month ORDER BY year_month; ``` - **关键点**:`DATE_FORMAT`直接生成标准年月格式,支持索引优化[^2] --- ##### **2. SQL Server** ```sql SELECT CONCAT(DATEPART(year, upload_time), '-', FORMAT(DATEPART(month, upload_time), '00')) AS year_month, COUNT(*) AS total_records FROM attachment GROUP BY DATEPART(year, upload_time), DATEPART(month, upload_time) ORDER BY year_month; ``` - **关键点**:`FORMAT(month, '00')`保证月份补零,避免`2023-1`格式错误[^1] --- ##### **3. PostgreSQL** ```sql SELECT TO_CHAR(created_at, 'YYYY-MM') AS year_month, SUM(CASE WHEN status='completed' THEN 1 ELSE 0 END) AS success_count FROM transactions GROUP BY year_month ORDER BY year_month; ``` - **关键点**:结合`TO_CHAR`和条件聚合实现复杂统计[^3] --- ##### **4. Oracle** ```sql SELECT TO_CHAR(order_date, 'YYYY-MM') AS year_month, AVG(amount) AS avg_amount FROM sales WHERE order_date >= TO_DATE('2022-01-01', 'YYYY-MM-DD') GROUP BY TO_CHAR(order_date, 'YYYY-MM') ORDER BY year_month; ``` - **关键点**:`TO_DATE`确保时间范围过滤准确性[^5] --- #### 进阶技巧 - **动态补零**:所有数据库均可通过`LPAD(month,2,'0')`或类似函数处理单数字月份 - **性能优化**:对日期字段建立索引,避免在`WHERE`/`GROUP BY`中对字段进行函数计算 - **跨年统计**:结合`YEAR()`和`MONTH()`分开分组可支持非连续年份数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值