想要找出mysql查询中两个日期之间的所有财务年度列表

时间:2017-03-09 19:18:28

标签: mysql

我有两张表,如下所示。

CREATE TABLE IF NOT EXISTS `order` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `loc_id` bigint(20) NOT NULL,
  `orderdate` date NOT NULL,
  `cash` double NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=8 ;

INSERT INTO `order` (`id`, `loc_id`, `orderdate`, `cash`) VALUES
(1, 1, '2012-02-09', 120),
(2, 2, '2011-07-21', 100),
(3, 3, '2005-04-25', 180),
(4, 1, '2008-12-01', 300),
(5, 2, '2014-07-21', 100),
(6, 3, '2004-04-25', 180),
(7, 1, '1998-12-01', 300);

另一个是

CREATE TABLE IF NOT EXISTS `location` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `loc_name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

INSERT INTO `location` (`id`, `loc_name`) VALUES
(1, 'region1'),
(2, 'region2'),
(3, 'region3');

我想知道所有地区财政年度的所有现金总额。

所以我的选择语句就像:

SELECT
    CASE
        WHEN MONTH(a.orderdate) <4 THEN CONCAT(YEAR(a.orderdate)-1,'-',YEAR(a.orderdate))
    ELSE
        CONCAT(YEAR(a.orderdate),'-',YEAR(a.orderdate)+1) END AS Fiscalyear,
SUM(a.cash),b.loc_name
FROM order as a JOIN location b on a.loc_id=b.id
WHERE YEAR(a.orderdate) BETWEEN 2005 AND 2012
GROUP BY Fiscalyear,a.loc_id

它的输出是:

Fiscalyear  | SUM(a.cash)   | loc_name  
2005-2006        |180           | region3    
2008-2009        |300           | region1    
2011-2012        |120           | region1    
2011-2012        |100           | region2

但我确实需要:

Fiscalyear  | SUM(a.cash)   | loc_name
2005-2006        |0             | region1    
2005-2006        |0             | region2     
2005-2006        |180           | region3    
2006-2007        |0             | region1 
2006-2007        |0             | region2       
2006-2007        |0             | region3    
2007-2008        |0             | region1    
2007-2008        |0             | region2       
2007-2008        |0             | region3    
2008-2009        |300           | region1    
2008-2009        |0             | region2    
2008-2009        |0             | region3    
2009-2010        |0             | region1    
2009-2010        |0             | region2    
2009-2010        |0             | region3    
2010-2011        |0             | region1  
2010-2011        |0             | region2    
2010-2011        |0             | region3   
2011-2012        |120           | region1    
2011-2012        |100           | region2   
2011-2012        |0             | region3

请帮我解决一下这个问题。 提前谢谢。

2 个答案:

答案 0 :(得分:0)

如果我理解正确,您希望列出所有会计年度和地区,无论是否有订单。一种方法是使用一个列出所有会计年度的表格,如下所示(我不使用MySQL,但这是它使用标准SQL的方式):

create table fiscal_years (
    year_name text not null,
    year_start date not null,
    year_end date not null,
    constraint years_pk primary key (year_start, year_end)
);

您可以使用所需的所有年份填充此表:

insert into fiscal_years (year_name, year_start, year_end)
values ('2007-2008', '2007-03-05', 2008-03-04');
-- (etc)

然后您可以使用区域CROSS JOIN来获取年份和地区的所有可能组合,然后使用订单表LEFT JOIN将它们组合在一起:

SELECT y.year_name, y.loc_name,
    COALESCE(sum (o.cash), 0) as cash_total
FROM (
  SELECT year_start, year_end, year_name,
  location.id as loc_id, loc_name
  FROM fiscal_years
  CROSS JOIN location
) y
LEFT JOIN orders o ON (
    y.year_start < o.orderdate
    and y.year_end >= o.orderdate
    and o.loc_id = y.loc_id
)
GROUP BY y.year_name, y.loc_name
ORDER BY y.year_name, y.loc_name;

LEFT JOIN返回联接左侧的所有行(在本例中为fiscal_yearslocation的笛卡尔积),无论右侧是否有匹配的行( orders),因此您始终会列出所有年份和所有地点。如果右侧没有匹配的行,则右侧的所有列都会返回NULL,因此使用COALESCE()代替返回零。

顺便说一下,你不应该使用像order这样的保留字作为表名 - 即使它没有引起语法错误,它至少也会引起混淆。

答案 1 :(得分:0)

SQL:

WHERE date_field >= '2018-04-01 00:00:00' AND date_field < '2018-04-01 00:00:00'

要使其通用,我们需要根据当前月份有条件地更改Year

WHERE date_field >= (
    SELECT 
        CASE WHEN MONTH(CURRENT_DATE)>= 4 THEN concat(
            YEAR(CURRENT_DATE), 
            '-04-01 00:00:00'
        ) ELSE concat(
            YEAR(CURRENT_DATE)-1, 
            '-04-01 00:00:00'
        ) END
) 
AND date_field < (
    SELECT 
        CASE WHEN MONTH(CURRENT_DATE)>= 4 THEN concat(
            YEAR(CURRENT_DATE)+ 1, 
            '-04-01 00:00:00'
        ) ELSE concat(
            YEAR(CURRENT_DATE), 
            '-04-01 00:00:00'
        ) END
)