考虑下表:
Person | 1/1/13 | 1/2/13 | 1/3/13 | 1/4/13 | 1/5/13
Bill | 4 | 2 | 1 | .5 | .25
Jane | 0 | 0 | 2 | 1 | .5
Mary | 0 | 8 | 4 | 2 | 1
-------------------------------------------------
Total | 4 | 10 | 7 | 3.5 | 1.75
这来自下表:
Bill | 1/1/13 | 4
Jane | 1/3/13 | 2
Mary | 1/2/13 | 8
基本上,我们知道第一天,然后我们假设每隔一天减少一半的价值。我想从第一张表中获得“总计”行。
有没有办法在(T-)SQL中执行此操作?我已经在R中创建了它,但我完全不知道如何在SQL中实现它。 (日期是实际日期,而不仅仅是星期几。)
答案 0 :(得分:1)
如果您的表格如下:
CREATE TABLE t (person VARCHAR(7), day_of_week_name VARCHAR(7), value NUMERIC);
INSERT INTO t VALUES ('Bill', 'Monday', 4);
INSERT INTO t values ('Jane', 'Weds', 2);
INSERT INTO t VALUES ('Mary', 'Tuesday', 8);
你有一些day_of_week
表格,其中包含天的相对位置:
CREATE TABLE day_of_week (name VARCHAR(7), position INT);
INSERT INTO day_of_week VALUES ('Monday', 1);
INSERT INTO day_of_week values ('Tuesday', 2);
INSERT INTO day_of_week VALUES ('Weds', 3);
INSERT INTO day_of_week VALUES ('Thurs', 4);
INSERT INTO day_of_week VALUES ('Friday', 5);
然后使用PIVOT
执行此操作 丑陋:
SELECT Monday, Tuesday, Weds, Thurs, Friday
FROM ( SELECT dow2.name AS day_of_week_name,
t.value / power(2, dow2.position - dow1.position) AS decayed_value
FROM t
JOIN day_of_week AS dow1
ON t.day_of_week_name = dow1.name
JOIN day_of_week AS dow2
ON dow1.position <= dow2.position
) AS b
PIVOT ( SUM(decayed_value)
FOR day_of_week_name
IN (Monday, Tuesday, Weds, Thurs, Friday)
) AS pvt
;
答案 1 :(得分:1)
with dow as (
select 'Monday' as dow, 1 as num union all
select 'Tuesday', 2 union all
select 'Wedneday', 3 union all
select 'Thursday', 4 union all
select 'Friday', 5 union all
select 'Saturday', 6 union all
select 'Sunday', 7
)
select dow.dow,
t.num * power(cast(0.5 as float), dow.dow - t.dow))
from (select t.*, dow.dow as dow
from t join
dow
on t.dow = dow.dow
) t join
dow
on t.dow >= dow.dow
group by t.name, dow.dow
这将以标准化格式获取数据。 。 。 ,,,。
如果你真的需要它进行透视(即,在列中进行),你可以使用pivot
关键字,或者进行条件聚合和。
答案 2 :(得分:0)
我创造了一个怪物,但它有效。
这是mysql,但我确信它很容易转换为tsql
select sum(mon)
, sum(tue)
, sum(wed)
, sum(thur)
, sum(fri)
from (
select person
, if (1 < field(day, 'mon', 'tue', 'wed', 'thur', 'fri'), 0, val / pow(2, 1 - field(day, 'mon', 'tue', 'wed', 'thur', 'fri'))) as mon
, if (2 < field(day, 'mon', 'tue', 'wed', 'thur', 'fri'), 0, val / pow(2, 2 - field(day, 'mon', 'tue', 'wed', 'thur', 'fri'))) as tue
, if (3 < field(day, 'mon', 'tue', 'wed', 'thur', 'fri'), 0, val / pow(2, 3 - field(day, 'mon', 'tue', 'wed', 'thur', 'fri'))) as wed
, if (4 < field(day, 'mon', 'tue', 'wed', 'thur', 'fri'), 0, val / pow(2, 4 - field(day, 'mon', 'tue', 'wed', 'thur', 'fri'))) as thur
, if (5 < field(day, 'mon', 'tue', 'wed', 'thur', 'fri'), 0, val / pow(2, 5 - field(day, 'mon', 'tue', 'wed', 'thur', 'fri'))) as fri
from (
(select 'bill' as person, 'mon' as day, 4 as val from dual)
union
(select 'jane', 'wed', 2 from dual)
union
(select 'mary', 'tue', 8 from dual)
) t
) tbl
答案 3 :(得分:0)
这样应该在sql server中工作:
with data
as (select ppl.name,
case
when ppl.day_of_week = 'Monday' then val
when 1 < day_val then 0
end monday,
case
when ppl.day_of_week = 'Tuesday' then val
when 2 < day_val then 0
else val * Power(Cast(0.5 as FLOAT), ( 2 - day_val ))
end Tuesday,
case
when ppl.day_of_week = 'Weds' then val
when 3 < day_val then 0
else val * Power(Cast(0.5 as FLOAT), ( 3 - day_val ))
end Weds,
case
when ppl.day_of_week = 'Thurs' then val
when 4 < day_val then 0
else val * Power(Cast(0.5 as FLOAT), ( 4 - day_val ))
end thurs,
case
when ppl.day_of_week = 'Friday' then val
when 5 < day_val then 0
else val * Power(Cast(0.5 as FLOAT), ( 5 - day_val ))
end friday
from (select name,
day_of_week,
val,
case day_of_week
when 'Monday' then 1
when 'Tuesday' then 2
when 'Weds' then 3
when 'Thurs' then 4
when 'Friday' then 5
end day_val
from person) ppl)
select coalesce(name, 'Total') as "Name",
Sum(monday) as "Monday",
Sum(tuesday) as "Tuesday",
Sum(weds) as "Weds",
Sum(thurs) as "Thursday",
Sum(friday) as "Friday"
from data
group by name with rollup
答案 4 :(得分:0)
以下查询假定存在此表变量:
DECLARE @data TABLE (
Person varchar(50),
Date date,
Value int
);
INSERT @data VALUES
('Bill', '2013-01-01', 4),
('Jane', '2013-01-03', 2),
('Mary', '2013-01-02', 8);
这是获取原始衰变数据的递归CTE方法:
WITH decay AS (
SELECT Person, Date, CAST(Value as float) AS Value
FROM @data
UNION ALL
SELECT Person, DATEADD(day, 1, Date) AS Date, Value / 2 AS Value
FROM decay
WHERE Value / 2 >= 0.25
)
SELECT Person, Date, SUM(Value) AS Value
FROM decay
GROUP BY Person, Date;
我想这可能会解决大多数人的需求,但是如果你需要它,你可以指定列的日期:
WITH decay AS (
SELECT Person, Date, CAST(Value as float) AS Value
FROM @data
UNION ALL
SELECT Person, DATEADD(day, 1, Date) AS Date, Value / 2 AS Value
FROM decay
WHERE Value / 2 >= 0.25
)
SELECT pvt.Person,
ISNULL(pvt.[2013-01-01], 0) AS [2013-01-01],
ISNULL(pvt.[2013-01-02], 0) AS [2013-01-02],
ISNULL(pvt.[2013-01-03], 0) AS [2013-01-03],
ISNULL(pvt.[2013-01-04], 0) AS [2013-01-04],
ISNULL(pvt.[2013-01-05], 0) AS [2013-01-05]
FROM (
SELECT Person, Date, SUM(Value) AS Value
FROM decay
GROUP BY Person, Date
) AS q
PIVOT (
SUM(Value)
FOR Date
IN ([2013-01-01], [2013-01-02], [2013-01-03], [2013-01-04], [2013-01-05])
) AS pvt;
这为您提供了结果集:
Person 2013-01-01 2013-01-02 2013-01-03 2013-01-04 2013-01-05
------------------------------------------------------------------
Bill 4 2 1 0.5 0.25
Jane 0 0 2 1 0.5
Mary 0 8 4 2 1
不幸的是,PIVOT要求您指定要旋转的行/列值/名称,以便必须动态生成查询。