4

次の表を検討してください。

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で行う方法について完全に困惑しています。(日付は曜日ではなく、実際の日付です。)

4

5 に答える 5

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キーワードを使用するか、条件付き集計の合計を実行できます。

于 2012-12-26T00:54:28.960 に答える
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
;

ここではSQLフィドル。

于 2012-12-26T00:52:02.420 に答える
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 では、ピボットする行/列の値/名前を指定する必要があるため、クエリを動的に生成する必要があります。

于 2016-12-19T21:00:32.240 に答える
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

http://sqlfiddle.com/#!2/d41d8/5249

于 2012-12-26T00:44:54.123 に答える
0

このようにSQLサーバーで動作するはずです:

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 

http://sqlfiddle.com/#!6/c4c6e/1

于 2012-12-26T00:46:56.737 に答える