【问题标题】:SQL and Fiscal year data retrievalSQL 和会计年度数据检索
【发布时间】:2013-07-06 00:38:30
【问题描述】:

我在尝试从我的数据库中检索财务数据时遇到问题。 例如,我用来计算月份之间数据的表格有月份和财政年度(即 1112(2012 年 11 月))。当我尝试计算 10 月至 12 月之间的 AMT 到期数据时,没有计算任何数据。但是,当我计算 1 月 - 9 月之间的数据时,它没有问题,但未能合并 fy(OCT NOV DEC) 开头的数据,导致数据不准确。

M_Y       Amt Due   dept    FY
1112      362.44     D2     2013
1212      10.50      D4     2013
0213      55.55      D1     2013

@LF = CAST((CAST@Current_FY_IN AS INT)-1) AS CHAR)
@startdate = @LFy + '10'
@enddate = CASE SUBSTRING(@mon_IN,1,1) WHEN '1' THEN @LY+@mon_IN ELSE @Current_FY_IN+@month_IN
@Current_FY_IN  (i.e. 2013) 
END

我知道这个问题,但我似乎无法解决这个问题。我希望有人就此事发表意见。

 SELECT M_Y, ISNULL(SUM(Amt Due),0) AS AmtDueNow 
      FROM FYAmmountDue 
      WHERE
'20' + RIGHT(M_F,2) + LEFT(M_F,2) BETWEEN @startdate AND @enddate - 1 
 AND FY = @Current_FY_IN 

【问题讨论】:

    标签: sql sql-server-2008 data-retrieval


    【解决方案1】:

    您依赖于 BETWEEN 运算符,这可能会给您带来令人惊讶的结果,而 可能会将这些列解释为数字,但 dbms 会将其解释为 char(n) 或 varchar(n) .对于不完整的日期尤其如此。

    最简单的方法是避免完全计算,只需在 WHERE 子句中命名您想要的月份。防御性编程也将命名财政年度。

    WHERE M_Y IN ('1012', '1112', '1212') 
      AND FY = 2013
    

    更好的方法是以保留有用(和合理)语义的方式修复您的存储。以下是存储会计期间的两种不同方式,“月优先”和“年优先”。

    drop table fiscal_periods;
    create table fiscal_periods (
      y_m char(4) not null unique,
      m_y char(4) not null unique
    );
    
    insert into fiscal_periods values ('1201', '0112');
    insert into fiscal_periods values ('1202', '0212');
    insert into fiscal_periods values ('1203', '0312');
    insert into fiscal_periods values ('1204', '0412');
    insert into fiscal_periods values ('1205', '0512');
    insert into fiscal_periods values ('1206', '0612');
    insert into fiscal_periods values ('1207', '0712');
    insert into fiscal_periods values ('1208', '0812');
    insert into fiscal_periods values ('1209', '0912');
    insert into fiscal_periods values ('1210', '1012');
    insert into fiscal_periods values ('1211', '1112');
    insert into fiscal_periods values ('1212', '1212');
    insert into fiscal_periods values ('1301', '0113');
    insert into fiscal_periods values ('1302', '0213');
    insert into fiscal_periods values ('1303', '0313');
    insert into fiscal_periods values ('1304', '0413');
    insert into fiscal_periods values ('1305', '0513');
    insert into fiscal_periods values ('1306', '0613');
    insert into fiscal_periods values ('1307', '0713');
    insert into fiscal_periods values ('1308', '0813');
    insert into fiscal_periods values ('1309', '0913');
    insert into fiscal_periods values ('1310', '1013');
    insert into fiscal_periods values ('1311', '1113');
    insert into fiscal_periods values ('1312', '1213');
    

    现在尝试一个简单的查询,首先是月份。

    -- Select the periods between Oct 2012 and Feb 2013
    select m_y
    from fiscal_periods
    where m_y between '1012' and '0213'
    order by m_y;
    -- Returns the empty set.
    

    相同的查询,年份优先。

    select y_m
    from fiscal_periods
    where y_m between '1210' and '1302'
    order by y_m;
    
    y_m 
    --
    1210
    1211
    1212
    1301
    1302
    

    更好的是,避免 Y2K 问题并将年份存储为四位数:201201、201302 等。

    【讨论】:

    • 感谢您的意见,迈克。我尝试这样做,但是这是一个脚本,它将根据用户输入动态生成报告。这么难的编码是没有用的。
    • @J.Ballard:然后修复您的存储格式,以便 BETWEEN 运算符正常工作。与其存储为“mmyy”,不如存储为“yymm”。存储为 'yymm' 会自然而然地排序,并且 BETWEEN 运算符也可以正常工作。
    【解决方案2】:

    您可以编写一个用户定义的函数来返回给定日期的会计年度...

        CREATE FUNCTION dbo.fFiscalYear(@calendarDt DateTime)
          RETURNS Int
        (
            DECLARE @year Int
            SET @year = YEAR(@calendarDt)
            IF MONTH(@calendarDt) NOT IN (10, 11, 12)
               SET @year = @year - 1
            RETURN @year
        )
        GO
    
    GRANT EXECUTE ON dbo.fFiscalYear TO  PUBLIC
    GO
    

    这是一个非常轻量级的函数,您现在可以在查询中使用它。

    这是一个例子:

     SELECT CONVERT(varchar(4), trans_dt, 12) AS m_y
            COALESCE(SUM(amt_due), 0) AS amt_due_now,
            dbo.fFiscalYear(trans_dt) AS fiscal_year
       FROM TransactionTable
            GROUP BY CONVERT(varchar(4), trans_dt, 12), dbo.fFiscalYear(trans_dt) 
            ORDER BY dbo.fFiscalYear(trans_dt), CONVERT(varchar(4), trans_dt, 12)
    

    如果 m_y 已经在您的数据库中,您可以将它用于您的 BETWEEN 选择,只要所有内容都在同一个世纪。

    【讨论】:

    • 谢谢柯特。 bewteen 函数在硬编码时返回我需要的所有内容。但这是一个开始。我仍然无法获得两位数月份的金额!
    • @J.Ballard M_Y 是整数还是字符串类型?
    • @J.Ballard 我之前回答过这个问题,但我的回答似乎消失了。将 M_Y 变量定义为 FULL 年份 * 100 + 月份数(例如,2013 年 3 月将是 201303)。这样,BETWEEN 运算符将在所有月份和年份中正常工作,即使对于跨越世纪或千年边界的日期范围,查询也将正常工作。
    • FYI M_Y in char。我如何将其定义为一整年?
    • 假设定义的字段长度已经足够长(varchar(6) 或更长)类似于“UPDATE MyTable SET M_Y = CONVERT(Varchar(6), transaction_dt, 112)”(使用适当的表和字段名,当然)。如果该字段没有被索引,它应该是。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-04
    • 2014-07-20
    • 2018-12-20
    • 1970-01-01
    • 2016-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多