繁体   English   中英

获取今天,上周同一天和去年同一天售出的商品

[英]Get UnitsSold for Today, Same day last week and same day last year

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

这是我当前的查询:

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值-我只是不确定如何执行这个复杂的查询。

让我知道您是否需要更多信息。

谢谢,

迈克尔

NRF零售日历是专门为解决销售比较业务问题而创建的- 零售业在1930年代通过将日历标准化为“ 4-5-4”日历解决了这一问题 ,每个孕期的第一个月有4个日历周,第二个为5周,第三个为4周,每4个季度52周,每年364天。 他们通过定期进行53周的工作来解决了另一个问题- 更多详细信息,请在下面引用 )。 它说明leap年,并确保始终将星期五与星期五进行比较。

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

4-5-4日历可作为零售行业的自愿指南,并通过根据4周– 5周– 4周的格式将年份分为几个月来确保各年之间的销售可比性。 日历的布局使假期排成一行,并确保可比较月份中星期六和星期日的数量相同。 因此,出于销售报告目的,将相似天与相似天进行比较。


步骤1:设定

通过将此日历建模为一些dbo.RetailTime表,您可以更轻松地比较来自正确日期的销售dbo.RetailTime TY week 26 day 6LY week 26 day 6以实际日历日期为准)进行比较。 日历是时间概念的抽象

像这样:

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进一步QuarterDay此内容。 零售商通常会将YearYearWeek以标识每个日历周,因此,2013年的第26周将为“ 201326”。

然后,编写脚本以将NRF日历数据导入模型中,然后可以创建函数,存储过程,视图或其他内容,为LYLLY (2年前)字段提供RetailTimeId (可能都为null)(用于日历表中的每个Id )。

结果为您提供了类似的信息(以下假设是每小时24小时的小时级别的粒度):

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

这给你一个查找表(它坚持到实际dbo.RetailTimeLookup与表不痛), Id为LY&LLY,每个ID在你dbo.RetailTime表( RetailTimeId )。 由于需要53周的时间,因此您需要在RetailTimeId列上具有唯一的索引,而在其他两个列上则RetailTimeId ,因此您可能希望将第53周与同年的第1周进行比较。


步骤2:与您的销售数据相关

下一步是通过将“ date”部分(不含“ time”部分)与RetailTime.Date和“ time”部分(以及小时)与RetailTime.DayHour进行匹配来查找与PaymentDate对应的Id 这可能是一项昂贵的操作 ,您可能更喜欢安排一个预定的隔夜流程(ETL),该RetailTimeIdPaymentDate已经查询了PaymentDateRetailTimeId填充“ SalesInfo”数据表,因此销售时,您的数据格式应如下所示:

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

数字的含义

我将CostAmountRetailAmountCurrentAmount放在其中是因为从业务的角度来看,知道销售的单位是好的,但它并不能告诉您这些销售的利润率-如果您以高折价,您的毛利率(GM%)可能很小,甚至是负数,而售出一半的TY可能会变得好得多……如果库存以健康的速度增长,每一点信息都与另一种,一种或另一种方式相关。

GM%为(1-CostAmount/CurrentAmount)*100这是每套西装都需要知道的获利能力数字。 折扣百分比为(1-CurrentAmount/RetailAmount)*100这就是您的销售折扣率。 单单一个“售出单位”的数字并不能说明什么。 零售界有句俗话:“ 销售是虚荣心,利润是理智 ”。 但是我在漂移。 这个想法是在您的详细销售数据中包含尽可能多的信息-并且确实包括产品(理想情况下是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年尚无记录),但这并不是您想要的,尽管所有信息已经存在。

如果您采用了上述方法并选择了一个临时表(或将其用作子查询),则需要执行以下操作以便仅获取您感兴趣的图形:

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

...但这只是比较星期五的销售额。 如果要计算与上一年WeekDay = 6的星期至今(WTD)金额,则只需在两个WHERE子句WeekDay = 6替换为WeekDay <= 6 这就是为什么我放SUMGROUP BY

注意

TY和LY之间的百分比差异为(TY/LY - 1) * 100 如果您有多个销售点(/商店),则LY的商店可能少于TY,这妨碍了比较。 零售商已经通过门之间的百分比差异解决了另一个问题,通常称为“ 补偿增加”。 这是通过不仅排队 (“时间”维度)实现的,又哪里 (“商店”维度),仅占该被打开LY,忽略“ 非补偿店 ”的商店。 对于打破数字下降一个产品层次的报道, 什么也需要与一些产品的数据联接。


最后一件事

这样做的目的是将苹果与苹果进行比较 -有一个原因需要您提取这些数字:每个零售商都想知道它们是否比LY数字有所提高。 任何人都可以将两个数字相除并得出一个百分比数字。 不幸的是,在现实世界中,报告准确的数据并不总是那么简单。

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

如果您将提供的值组合为正确的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部分。

如果我正确理解您的问题,则只需要一个查询即可获得3个结果。

您可以union all使用union all

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

UPDATE

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

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行。 如果需要,您还可以添加一个伪造的列,说明该图表的当前日期(今天,上周,去年)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM