获取UnitsSold for Today,去年同一天和去年同一天

时间:2013-08-02 15:45:55

标签: c# asp.net sql sql-server

我正在尝试构建一个多子查询查询,以便我可以将结果数据绑定到图表

这是我目前的查询:

SELECT TOP (100) PERCENT Sum(DBO.ORDERLINE.QTY)               AS UnitsSold, 
                         { fn HOUR(dbo.[Order].PaymentDate) } AS MyHour 
FROM   DBO.[ORDER] 
       INNER JOIN DBO.ORDERLINE 
               ON DBO.[ORDER].ORDERID = DBO.ORDERLINE.ORDERID 
WHERE  ( DBO.[ORDER].WEBSITEID = 2 ) 
       AND ( DBO.[ORDER].ORDERSTATUSID = 2 ) 
       AND ( Day(DBO.[ORDER].PAYMENTDATE) = 01 ) 
       AND ( Month(DBO.[ORDER].PAYMENTDATE) = 08 ) 
       AND ( Year(DBO.[ORDER].PAYMENTDATE) = 2013 ) 
GROUP  BY { fn HOUR(dbo.[Order].PaymentDate) } 

这会根据昨天的数据返回两列,UnitsSold和MyHour - 这很有用..

但是我想在上周同一天获得相同数据,去年同一天,我可以通过c#自己提供MONTH / DAY / YEAR值 - 我只是不知道怎么做复杂的查询。

如果您需要更多信息,请与我们联系。

谢谢,

迈克尔

3 个答案:

答案 0 :(得分:4)

NRF Retail Calendar专门用于解决销售比较的业务问题 - 零售行业通过将日历标准化为&#来解决了这个问题在1930年的 34; 4-5-4"日历,每个学期的第一个月有4个星期,第二个月有5个星期,第三个有4个星期,4个星期有52个星期,每年有364天。他们通过定期进行53周的年度来解决这个问题 - more details here, quote below)。它占据了闰年,并确保星期五总是与星期五相比。

  

4 - 5 - 4日历的目的是什么?

     

4-5-4日历作为零售行业的自愿指南,并确保年份之间的销售可比性,将年份除以基于4周 - 5周 - 4周格式的月份。日历的布局与假期相符,并确保在可比月份的星期六和星期日相同的数量。因此,将日期与销售报告目的的日期进行比较。


第1步:设置

通过将此日历建模到某个dbo.RetailTime表格中,您可以更轻松地比较正确日期的销售额 - TY week 26 day 6LY week 26 day 6进行比较,以实际日历日期为准是即可。日历是 time 概念的抽象

这样的事情:

public interface IRetailTime
{
    DateTime Date { get; } // does not have "time" info ("00:00:00")
    int DayHour { get; }
    int WeekDay { get; }
    int YearWeek { get; }
    int YearMonth { get; }
    int YearQuarter { get; }
    int Year { get; }
}

根据您的报告需求,您可以通过添加字段QuarterDayQuarterWeekQuarterMonthMonthDayMonthWeek来进一步加强这一点。零售商通常将YearYearWeek联系起来以确定每个日历周,因此2013年的第26周将是" 201326"。

然后你编写一个脚本将NRF日历数据导入到模型中,你可以创建一个函数,存储过程,视图或其他任何东西,为RetailTimeId提供LY,并且,哎呀为什么不,对于日历表中的每个LLY Id(2年前)字段(可以都为空)。

结果给你这样的东西(下面假设小时级粒度,每天24小时):

    RetailTimeId   LYId   LLYId
               1    NULL   NULL
               2    NULL   NULL
             ...     ...    ...
            8737       1   NULL
            8738       2   NULL
             ...     ...    ...
           17472    8737      1
           17473    8738      2
             ...     ...    ...

这为您提供了一个查找表(将其持久保存到实际dbo.RetailTimeLookup表并不会受到伤害),{L}& Id LLY,针对dbo.RetailTime表格中的每个ID(RetailTimeId)。您需要RetailTimeId列上的唯一索引,而不是其他两个索引,因为53周的年份,您可能希望比较第53周和第1周同年。


第2步:与销售数据相关

下一步是通过匹配"日期"来查找与您的Id对应的PaymentDate。部分(没有"时间"部分)与RetailTime.Date和"时间"使用RetailTime.DayHour的部分(只是小时)。 这可能是一项昂贵的操作,您可能更喜欢使用预定的隔夜流程(ETL)来填充" SalesInfo" RetailTimeId PaymentDate的数据表已经被查询,因此销售时您的数据格式如下:

public interface ISalesInfo
{
    int RetailTimeId { get; }
    int UnitsSold { get; }
}

缺少的是与上面的TY / LY / LLY查找视图的连接,您现在可以"切片"您的销售数字在"时间"维度 - 我曾经为今年的销售提供了一个视图,并且在最低的粒度级别为去年的销售提供了另一个视图,如下所示:

CREATE VIEW vwSALES_TY AS
BEGIN

    SELECT t.Id RetailTimeId,
           t.Year, 
           t.YearQuarter, 
           t.YearMonth, 
           t.YearWeek, 
           t.WeekDay, 
           t.DayHour,
           sales.UnitsSold Units                -- total units sold
           --,sales.CostAmount CostAmount       -- cost value of sold units
           --,sales.RetailAmount RetailAmount   -- full-price value of sold units
           --,sales.CurrentAmount CurrentAmount -- actual sale value of sold units
    FROM dbo.RetailTime t
        INNER JOIN dbo.SalesInfo sales ON t.Id = sales.RetailTimeId
    WHERE t.Year = 2013

END

CREATE VIEW vwSALES_LY AS
BEGIN

    SELECT t.Id RetailTimeId,
           t.Year, 
           t.YearQuarter, 
           t.YearMonth, 
           t.YearWeek, 
           t.WeekDay, 
           t.DayHour,
           sales.UnitsSold Units                -- total units sold
           --,sales.CostAmount CostAmount       -- cost value of sold units
           --,sales.RetailAmount RetailAmount   -- full-price value of sold units
           --,sales.CurrentAmount CurrentAmount -- actual sale value of sold units
    FROM dbo.RetailTime t
        INNER JOIN dbo.SalesInfo sales ON t.Id = sales.RetailTimeId
    WHERE t.Year = 2012

END
  

数字的含义

     

我把 CostAmount RetailAmount CurrentAmount 放在那里,因为从商业的角度来看,知道售出的单位是好的,但它没有&#39告诉你这些销售是多么有利可图 - 你可能已售出两倍的LY单位,如果你以高折扣价出售它们,你的毛利率(GM%)可能会非常微弱甚至是负面的,而卖出一半就是许多单位TY可能会成为一个更好,更好的情况......如果库存正在以健康的速度转变 - 每一点信息都与另一种信息有关,无论如何。

     

GM%是(1-CostAmount/CurrentAmount)*100 - 这是每个诉讼需要知道的盈利数字。 %折扣为(1-CurrentAmount/RetailAmount)*100 - 这是您的销售折扣率。 A"销售单位"单独的数字并不能说明多少; “零售世界”中有一句谚语" 销售是为了虚荣,为了理智而获利"。但是我漂流了。我们的想法是在您的精细销售数据中包含尽可能多的信息 - 这包括产品(理想的是SKU),销售点甚至客户信息(如果可用)。任何遗漏的内容都无法进入报告。


第3步:......利润!

使用视图为您提供TY销售,而另一个为您提供LY销售准备好排队,剩下要做的就是询问数据库

SELECT t.Year, 
       t.YearQuarter, 
       t.YearMonth, 
       t.YearWeek, 
       t.WeekDay, 
       t.DayHour,
       SUM(ISNULL(ty.Units,0)) UnitsTY,
       SUM(ISNULL(ly.Units,0)) UnitsLY
FROM dbo.RetailTime t
    INNER JOIN dbo.RetailTimeLookup lookup ON t.Id = lookup.RetailTimeId
    LEFT JOIN dbo.vwSALES_TY ty ON lookup.RetailTimeId = ty.RetailTimeId
    LEFT JOIN dbo.vwSALES_LY ly ON lookup.LYId = ly.RetailTimeId
WHERE t.Year = 2013

现在,这将为2013年零售日历每一天的每小时提供TY与LY(保留2012年尚未成为2013年记录的2012年历史),但这还不是什么你想要的,虽然所有信息都已经存在。

如果您将上述内容和选中一个临时表(或将其用作子查询),您需要执行类似这样的操作才能获取您自己的数据。 ;对此感兴趣:

SELECT t.DayHour,
       SUM(lw.UnitsTY) LastWeekUnitsTY,
       SUM(lw.UnitsLY) LastWeekUnitsLY,
       SUM(tw.UnitsTY) ThisWeekUnitsTY,
       SUM(tw.UnitsLY) ThisWeekUnitsLY
FROM (SELECT DayHour FROM #above GROUP BY DayHour) t
    LEFT JOIN (SELECT UnitsTY, UnitsLY 
               FROM #above 
               WHERE YearWeek = 25 AND WeekDay = 6) lw 
        ON t.DayHour = lw.DayHour
    LEFT JOIN (SELECT UnitsTY, UnitsLY 
               FROM #above 
               WHERE YearWeek = 26 AND WeekDay = 6) tw
        ON t.DayHour = tw.DayHour
GROUP BY t.DayHour

......但这只是比较周五的销售情况。如果您想计算与前一年相符的一周至今(WTD)金额,您只需在WeekDay = 6个条款中将WeekDay <= 6替换为WHERE即可。这就是我将SUMGROUP BY放在一起的原因。

  

注意

     

TY和LY之间的%差异为(TY/LY - 1) * 100。如果您有多个销售点(/商店),那么您可能拥有的商店数量比TY少,并且可以阻止比较。零售商用门到门%差异来解决这个问题,通常被称为&#34; comp 增加&#34;。这不仅可以排列 何时 (&#34;时间&#34;尺寸),还可以 其中 < / strong>(&#34; store&#34;维度),仅考虑LY打开的商店,忽略&#34; 非comp商店&#34;。对于将数据分解为产品层次结构的报表, 内容 还需要加入一些产品数据。< / p>


最后一件事

这个想法是比较苹果和苹果 - 这就是你需要提取这些数字的原因:每个零售商都想知道他们是否在改善LY数字。任何人都可以划分两个数字并得出百分比数字。不幸的是,在现实生活中的商业世界中,报告准确的数据并不总是 简单。

免责声明:我在零售业工作了9年。

答案 1 :(得分:1)

如果您将这些值组合为正确转换的DATE变量,而不是将提供的值用作日期的一部分,则可以使用DATEADD()

SELECT TOP (100) PERCENT Sum(DBO.ORDERLINE.QTY)               AS UnitsSold, 
                         { fn HOUR(dbo.[Order].PaymentDate) } AS MyHour 
FROM   DBO.[ORDER] 
       INNER JOIN DBO.ORDERLINE 
               ON DBO.[ORDER].ORDERID = DBO.ORDERLINE.ORDERID 
WHERE  ( DBO.[ORDER].WEBSITEID = 2 ) 
       AND ( DBO.[ORDER].ORDERSTATUSID = 2 ) 
       AND ( DBO.[ORDER].PAYMENTDATE = @date 
              OR DBO.[ORDER].PAYMENTDATE = Dateadd(WEEK, -1, @date) 
              OR DBO.[ORDER].PAYMENTDATE = Dateadd(YEAR, -1, @date) ) 
GROUP  BY { fn HOUR(dbo.[Order].PaymentDate) } 

另请注意,如果您在等式的任何一端都有DATETIME作为数据类型,那么您希望CAST将它们DATE忽略TIME 1}}部分。

答案 2 :(得分:1)

如果我正确理解了您的问题,您只需要一个包含3个结果的查询。

您可以使用union all

这会将3个查询与不同的日期间隔组合在一起。 您将获得一个包含3行的结果集。

<强>更新

您可以合并这样的查询(未经过测试,而不是在我的电脑上)

SELECT TOP (100) PERCENT Sum(DBO.ORDERLINE.QTY) AS UnitsSold, { fn HOUR(dbo.[Order].PaymentDate) } AS MyHour 
FROM   DBO.[ORDER] 
       INNER JOIN DBO.ORDERLINE 
               ON DBO.[ORDER].ORDERID = DBO.ORDERLINE.ORDERID 
WHERE  ( DBO.[ORDER].WEBSITEID = 2 ) 
       AND ( DBO.[ORDER].ORDERSTATUSID = 2 ) 
       AND ( Day(DBO.[ORDER].PAYMENTDATE) = 01 ) 
       AND ( Month(DBO.[ORDER].PAYMENTDATE) = 08 ) 
       AND ( Year(DBO.[ORDER].PAYMENTDATE) = 2013 ) 
GROUP  BY { fn HOUR(dbo.[Order].PaymentDate) } 

union all

SELECT TOP (100) PERCENT Sum(DBO.ORDERLINE.QTY) AS UnitsSold, { fn HOUR(dbo.[Order].PaymentDate) } AS MyHour 
FROM   DBO.[ORDER] 
       INNER JOIN DBO.ORDERLINE 
               ON DBO.[ORDER].ORDERID = DBO.ORDERLINE.ORDERID 
WHERE  ( DBO.[ORDER].WEBSITEID = 2 ) 
       AND ( DBO.[ORDER].ORDERSTATUSID = 2 ) 
       AND ( Day(DBO.[ORDER].PAYMENTDATE) = 24 ) 
       AND ( Month(DBO.[ORDER].PAYMENTDATE) = 07 ) 
       AND ( Year(DBO.[ORDER].PAYMENTDATE) = 2013 ) 
GROUP  BY { fn HOUR(dbo.[Order].PaymentDate) } 

union all

SELECT TOP (100) PERCENT Sum(DBO.ORDERLINE.QTY) AS UnitsSold, { fn HOUR(dbo.[Order].PaymentDate) } AS MyHour 
FROM   DBO.[ORDER] 
       INNER JOIN DBO.ORDERLINE 
               ON DBO.[ORDER].ORDERID = DBO.ORDERLINE.ORDERID 
WHERE  ( DBO.[ORDER].WEBSITEID = 2 ) 
       AND ( DBO.[ORDER].ORDERSTATUSID = 2 ) 
       AND ( Day(DBO.[ORDER].PAYMENTDATE) = 01 ) 
       AND ( Month(DBO.[ORDER].PAYMENTDATE) = 08 ) 
       AND ( Year(DBO.[ORDER].PAYMENTDATE) = 2012 ) 
GROUP  BY { fn HOUR(dbo.[Order].PaymentDate) } 

您的数据将获得3行。如果你想要你也可以添加一个假columon说这是图表的今天(今天,上周,去年)