[英]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周的格式将年份分为几个月来确保各年之间的销售可比性。 日历的布局使假期排成一行,并确保可比较月份中星期六和星期日的数量相同。 因此,出于销售报告目的,将相似天与相似天进行比较。
通过将此日历建模为一些dbo.RetailTime
表,您可以更轻松地比较来自正确日期的销售dbo.RetailTime
TY week 26 day 6
与LY 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; }
}
您可以根据报告需求,通过添加字段QuarterDay
, QuarterWeek
, QuarterMonth
, MonthDay
和MonthWeek
进一步QuarterDay
此内容。 零售商通常会将Year
与YearWeek
以标识每个日历周,因此,2013年的第26周将为“ 201326”。
然后,编写脚本以将NRF日历数据导入模型中,然后可以创建函数,存储过程,视图或其他内容,为LY
和LLY
(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周进行比较。
下一步是通过将“ date”部分(不含“ time”部分)与RetailTime.Date
和“ time”部分(以及小时)与RetailTime.DayHour
进行匹配来查找与PaymentDate
对应的Id
。 这可能是一项昂贵的操作 ,您可能更喜欢安排一个预定的隔夜流程(ETL),该RetailTimeId
将PaymentDate
已经查询了PaymentDate
的RetailTimeId
填充“ 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
数字的含义
我将CostAmount , RetailAmount和CurrentAmount放在其中是因为从业务的角度来看,知道销售的单位是好的,但它并不能告诉您这些销售的利润率-如果您以高折价,您的毛利率(GM%)可能很小,甚至是负数,而售出一半的TY可能会变得好得多……如果库存以健康的速度增长,每一点信息都与另一种,一种或另一种方式相关。
GM%为
(1-CostAmount/CurrentAmount)*100
这是每套西装都需要知道的获利能力数字。 折扣百分比为(1-CurrentAmount/RetailAmount)*100
这就是您的销售折扣率。 单单一个“售出单位”的数字并不能说明什么。 零售界有句俗话:“ 销售是虚荣心,利润是理智 ”。 但是我在漂移。 这个想法是在您的详细销售数据中包含尽可能多的信息-并且确实包括产品(理想情况下是SKU),销售点,甚至包括客户信息(如果有)。 缺少的任何内容都永远无法写入报告。
在一个视图中 ,您可以得到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
。 这就是为什么我放SUM
和GROUP 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个结果。
这会将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.