我正在尝试构建一个多子查询查询,以便我可以将结果数据绑定到图表
这是我目前的查询:
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值 - 我只是不知道怎么做复杂的查询。
如果您需要更多信息,请与我们联系。
谢谢,
迈克尔
答案 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周格式的月份。日历的布局与假期相符,并确保在可比月份的星期六和星期日相同的数量。因此,将日期与销售报告目的的日期进行比较。
通过将此日历建模到某个dbo.RetailTime
表格中,您可以更轻松地比较正确日期的销售额 - TY week 26 day 6
与LY 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; }
}
根据您的报告需求,您可以通过添加字段QuarterDay
,QuarterWeek
,QuarterMonth
,MonthDay
和MonthWeek
来进一步加强这一点。零售商通常将Year
与YearWeek
联系起来以确定每个日历周,因此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周同年。
下一步是通过匹配"日期"来查找与您的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),销售点甚至客户信息(如果可用)。任何遗漏的内容都无法进入报告。
使用视图为您提供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
即可。这就是我将SUM
和GROUP 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说这是图表的今天(今天,上周,去年)