Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/76.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
sql获取两个日期之间的所有月份和年份,并根据两个日期之间的月份频率计算总数_Sql_Sql Server_Tsql - Fatal编程技术网

sql获取两个日期之间的所有月份和年份,并根据两个日期之间的月份频率计算总数

sql获取两个日期之间的所有月份和年份,并根据两个日期之间的月份频率计算总数,sql,sql-server,tsql,Sql,Sql Server,Tsql,雇员: emid stdt enddt 1 12jan2019 15dec2019 2 12mar2019 12apr2019 3 12mar2018 12apr2018 4 12feb2019 Null 工资表: empid salarypermonth 1 10000 2 20000 3 15000 4 10000 我想列出stdt和endt之间的所有月份和年份,总数应该是 月*工资 所需的o/p,如: month

雇员:

emid stdt      enddt 

1    12jan2019 15dec2019 
2    12mar2019 12apr2019
3    12mar2018 12apr2018
4    12feb2019 Null
工资表:

empid salarypermonth
1     10000
2     20000
3     15000
4     10000
我想列出stdt和endt之间的所有月份和年份,总数应该是 月*工资

所需的o/p,如:

month year  total expenditure
jan   2019  10000
feb   2019  10000
mar   2019  30000  -- total salary of 1 and 2 as employee 1 and 2 both got salary in mar
....
....
mar   2018  15000
....
等等

基本上,我想报告雇主每月和每年的工资支出。
假设员工根据薪资表获得薪资,而不考虑加入日期。

您可以使用递归CTE展开数据,然后聚合:

with cte as (
      select datefromparts(year(e.stdt), month(e.stdt), 1) as yyyymm,
             e.enddt, e.emid, s.salary
      from employee e join
           salary s
           on e.emid = s.empid
      union all
      select dateadd(month, 1, yyyymm), enddt, emid, salary
      from cte
      where eomonth(yyyymm) < enddt
     )
select yyyymm, sum(salary)
from cte
group by yyyymm
order by yyyymm;

另一种方法是使用Tall和>=删除SQLite标记。根据大量证据,这似乎是SQL Server。事实上,您以2019年1月12日等格式编写了日期,这表明您将其存储为varchar而不是日期;是这样吗?我希望不是。或者,您要查找的查询不会像现在这样与列匹配;因为一个表中有日期/varchar,另一个表中有varchar和年份。“这里有些不太理想的设计选择。我们这里不是在谈论甲骨文,”Joedbahaha说。Oracle也不以某种格式存储日期。如果您在Oracla数据库中看到它们,那是因为有人选择了错误的数据类型。@Larnu。我不会做出这样的假设。人们似乎根据个人喜好在问题中写上日期。为什么提问者不使用YYYY-MM-DD格式——这是标准的ISO 8601格式,明确无误,且区域设置安全——我无法理解。2019年1月12日为了便于参考,我在sql server中以01-12-2019格式记录了日期
USE Sandbox;
GO

CREATE TABLE dbo.Employee (emid int,
                           stdt date,
                           enddt date);
INSERT INTO dbo.Employee (emid,
                          stdt,
                          enddt)
VALUES (1, '20190112', '20191215'),
       (2, '20190312', '20190412'),
       (3, '20180312', '20190418'),
       (4, '20190212', NULL);
GO

CREATE TABLE dbo.Salary (empid int,
                         salarypermonth int);
GO

INSERT INTO dbo.Salary (empid,
                        salarypermonth)
VALUES (1, 10000),
       (2, 20000),
       (3, 15000),
       (4, 10000);
GO

WITH N AS(
    SELECT N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
    SELECT TOP (SELECT MAX(DATEDIFF(MONTH, stdt,GETDATE())) FROM dbo.Employee)
           ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 AS I
    FROM N N1, N N2), --100 months. Add more for more months
Dates AS(
    SELECT DATEADD(MONTH,T.I,E.stdt) AS MonthStart,
           EOMONTH(DATEADD(MONTH,T.I,E.stdt)) AS MonthEnd
    FROM Tally T
         CROSS APPLY (SELECT MIN(stdt) AS stdt FROM dbo.Employee) E)
SELECT DATENAME(MONTH, D.MonthStart)AS [Month],
       DATEPART(YEAR,D.MonthStart) AS [Year],
       SUM(S.salarypermonth) AS Salaries
FROM Dates D
     LEFT JOIN dbo.Employee E ON (D.MonthStart <= E.enddt OR E.enddt IS NULL)
                             AND D.MonthEnd >= E.stdt
     LEFT JOIN dbo.Salary S ON E.emid = S.empid
GROUP BY DATENAME(MONTH, D.MonthStart),
         DATEPART(YEAR,D.MonthStart)
ORDER BY CONVERT(date,CONCAT('01 ',DATENAME(MONTH, D.MonthStart),DATEPART(YEAR,D.MonthStart)),106) ASC;

GO
DROP TABLE dbo.Employee;
DROP TABLE dbo.Salary;