我的结果集始终以这种格式显示:
LocationId Wed Thu Fri Sat Sun Mon Tue
生成这些列的函数的输入接受开始日期,并生成7天的数量报告。因此,如果我输入'2014-02-01',则列将始终按该顺序出现,即使该特定日期是星期六(日期“环绕”)。
我需要每列的日期,以便计算另一个值(称为“费用”),该值基于每个位置的开始日期和结束日期。例如,对于日期'2014-01-01'到'2014-02-03',位置21可能具有与其关联的值50,但是从'2014-02-04'它具有值53。值在当天列中指的是销售。因此,如果有一个值(甚至为0),则表示SalesPerson存在且他应该收到AppearanceFee。其中一个困难是计算该人在特定日期应该收到的费用,因为报告没有生成日期。您拥有的唯一信息是开始日期。
例如
LocationId | Value | StartDate | EndDate
-----------+-------+------------+-----------
21 | 50 | 2014-01-01 | 2014-02-03
21 | 53 | 2014-02-04 | null
要模拟一条记录,可以使用此查询:
declare @startdate datetime
select @startdate = '2014-02-01'
select *
, 0 as Fee -- How do I calculate this value?
from
(
select 21 as LocationId
, 30 as Wed
, 33 as Thu
, 36 as Fri
, NULL as Sat
, NULL as Sun
, 19 as Mon
, 24 as Tue
) record
我想过每天使用一个复杂的case语句,但是有一个更简单的方法吗?
CASE Left(DATENAME(dw, @startdate), 3)
WHEN 'Wed' THEN
(
(SELECT IsNull(Wed, 0) * Value FROM LocationValue lv WHERE lv.LocationId = record.LocationId AND @startdate BETWEEN lv.StartDate and IsNull(lv.EndDate, '2050-12-31')) +
(SELECT IsNull(Thu, 0) * Value FROM LocationValue lv WHERE lv.LocationId = record.LocationId AND DateAdd(dd, 1, @startdate) BETWEEN lv.StartDate and IsNull(lv.EndDate, '2050-12-31')) +
(SELECT IsNull(Fri, 0) * Value FROM LocationValue lv WHERE lv.LocationId = record.LocationId AND DateAdd(dd, 2, @startdate) BETWEEN lv.StartDate and IsNull(lv.EndDate, '2050-12-31')) +
(SELECT IsNull(Sat, 0) * Value FROM LocationValue lv WHERE lv.LocationId = record.LocationId AND DateAdd(dd, 3, @startdate) BETWEEN lv.StartDate and IsNull(lv.EndDate, '2050-12-31')) +
(SELECT IsNull(Sun, 0) * Value FROM LocationValue lv WHERE lv.LocationId = record.LocationId AND DateAdd(dd, 4, @startdate) BETWEEN lv.StartDate and IsNull(lv.EndDate, '2050-12-31')) +
(SELECT IsNull(Mon, 0) * Value FROM LocationValue lv WHERE lv.LocationId = record.LocationId AND DateAdd(dd, 5, @startdate) BETWEEN lv.StartDate and IsNull(lv.EndDate, '2050-12-31')) +
(SELECT IsNull(Tue, 0) * Value FROM LocationValue lv WHERE lv.LocationId = record.LocationId AND DateAdd(dd, 6, @startdate) BETWEEN lv.StartDate and IsNull(lv.EndDate, '2050-12-31'))
)
正如你所看到的,这个案例陈述相当笨拙。
答案 0 :(得分:1)
我设法使用PIVOT和UNPIVOT的组合以及生成日期范围的查询来解决这个问题。
DECLARE @startDate DATETIME = '2014-02-01'
DECLARE @endDate DATETIME = @startDate + 7
SELECT
LocationId,
Sum(Wed) Wed,
Sum(Thu) Thu,
Sum(Fri) Fri,
Sum(Sat) Sat,
Sum(Sun) Sun,
Sum(Mon) Mon,
Sum(Tue) Tue,
Sum(Fee) Fee
FROM
(
SELECT
af.LocationId,
Calendar.Day,
Date,
Sales,
IsNumeric(Sales) * Value AS Fee
FROM
(
SELECT
Left(DateName(DW, datetable.Date), 3) Day,
Convert(DATE, datetable.Date) Date
FROM (
SELECT DATEADD(DAY, -(a.a + (10 * b.a) + (100 * c.a)), getdate()) AS Date
FROM (SELECT 0 AS a
UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS a
CROSS JOIN (SELECT 0 AS a
UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS b
CROSS JOIN (SELECT 0 AS a
UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS c
) datetable
WHERE datetable.Date BETWEEN @startDate AND @endDate
) Calendar LEFT JOIN
(
SELECT
LocationId,
Day,
Sales
FROM dbo.f_FakeReport(@startDate) AS Report
UNPIVOT
(
Sales
FOR Day IN (Wed, Thu, Fri, Sat, Sun, Mon, Tue)
) U) AS Report
ON Calendar.Day = Report.Day
LEFT JOIN AppearanceFee af
ON af.LocationId = Report.LocationId
AND date BETWEEN af.StartDate AND IsNull(af.EndDate, '2099-12-21')
) data
PIVOT
(
Sum(Sales)
FOR Day IN (Wed, Thu, Fri, Sat, Sun, Mon, Tue)
) pvt
WHERE LocationId IS NOT NULL
GROUP BY LocationId