I am using #standardSQL BigQuery and want to be able to count unique values across columns.
I want to count the number of distinct values across my user funnel per visit_id which are stored in the following columns: first_pgroup,second,third,forth,fifth,sixth,seventh,eighth,ninth,tenth.
I have the following table:
visit_id
first_pgroup
second
third
forth
fifth
sixth
seventh
eighth
ninth
tenth
1
cloth
cloth
cloth
cloth
cloth
cloth
cloth
cloth
cloth
cloth
2
shoes
cloth
beauty
3
beauty
4
home&living
cloth
home&living
shoes
accessories
5
shoes
shoes
shoes
shoes
shoes
shoes
My goal is to be able to create a new column which states the unique values in each row.
The desired output is:
Here is my query:
> WITH
> config AS (
> SELECT
> --SET time frame
> DATE "2022-01-01" AS start_date,
> DATE "2022-01-01" AS end_date ),
>
>
> PDP_table AS (
> SELECT
> DISTINCT
> request_id AS request_id_PDP,
> eventType,
> SAFE_CAST(pid AS STRING) AS pid,
> SPLIT(pgroup , '/')[SAFE_OFFSET(0)] as product_group
>
> FROM
> `project.table`,
> config
> WHERE
> DATE(PARTITIONTIME) BETWEEN config.start_date
> AND config.end_date
> AND pid IS NOT NULL
> and eventType = "view" ),
>
> table AS ( SELECT
> timestamp,
> visit_id,
> request_id, FROM
> `project.table.2`,
> config WHERE
> DATE(PARTITIONTIME) BETWEEN config.start_date
> AND config.end_date
> AND site IN ('Live2',
> 'App'
> )AND country = 'de'),
> raw as ( SELECT
> cast((b.product_group) as string) AS first_pgroup,
> cast(LEAD( b.product_group, 1) OVER (PARTITION BY visit_id ORDER BY request_id) as string) AS second, cast( LEAD(
> b.product_group, 2) OVER (PARTITION BY visit_id ORDER BY request_id)as
> string) AS third,
> cast(LEAD( b.product_group, 3) OVER (PARTITION BY visit_id ORDER BY request_id)as string) AS forth,
> cast(LEAD( b.product_group, 4) OVER (PARTITION BY visit_id ORDER BY request_id) as string) AS fifth, cast( LEAD(
> b.product_group, 5) OVER (PARTITION BY visit_id ORDER BY request_id)
> as string) AS sixth, cast( LEAD( b.product_group, 6) OVER (PARTITION
> BY visit_id ORDER BY request_id) as string) AS seventh, cast( LEAD(
> b.product_group, 7) OVER (PARTITION BY visit_id ORDER BY request_id
> )as string) AS eighth, cast( LEAD( b.product_group, 8) OVER (PARTITION
> BY visit_id ORDER BY request_id) as string) AS ninth,
> cast(LEAD( b.product_group, 9) OVER (PARTITION BY visit_id ORDER BY request_id) as string) AS tenth FROM
> table a JOIN
> PDP_table b ON
> b.request_id_PDP = a.request_id
> )
> select *, (
> select count(distinct category) - 1
> from unnest(values(replace(to_json_string(t), 'null', '"null"'))) category
> where category != 'null' ) as category_count from raw
Following approached worked based on Mikahils answer:
select *, (select count(distinct category) from
unnest([first_pgroup,second,third,forth,fifth,sixth,seventh,eighth,ninth,tenth])
as category where category != 'null') as cat_count from raw
Consider below approach
create temp function values(input string) returns array<string> language js as """
return Object.values(JSON.parse(input));
""";
select *, (
select count(distinct category) - 1
from unnest(values(replace(to_json_string(t), 'null', '"null"'))) category
where category != 'null'
) as category_count
from your_table t
if applied to sample data in y our question - output is
If you want to use just sql to solve this, below approach is much simple and works across multiple databases
with main_table
as
(select visit_id,first_group group_value from table
union all
select visit_id,second_group from table
union all
select visit_id,third_group from table
union all
select visit_id,fourth_group from table
union all
select visit_id,fifth_group from table
union all
select visit_id,sixth_group from table
union all
select visit_id,seventh_group from table)
select s.*,count(distinct m.group_value) distint_count
from main_table m
left join table s
on m.visit_id=s.visit_id
Related
I am working on pulling some data from a table.
declare #SampleData as Table(Id int, ContactId int, Item varchar(25),CreatedOn date)
insert into #SampleData
VALUES(100,2500,'Some item name 1212', '9/5/2020'),
(104,2500,'Some item name 2232', '9/15/2020'),
(109,2500,'Some item name 3434', '9/20/2020'),
(112,3000,'Some item name 5422', '8/1/2020'),
(132,3000,'Some item name 344', '9/5/2020'),
(134,3000,'Some item name 454', '9/15/2020'),
(139,3500,'Some item name 6455', '7/5/2020'),
(146,3500,'Some item name 546', '8/5/2020'),
(142,3500,'Some item name 867', '9/5/2020'),
(149,3500,'Some item name 677', '9/15/2020'),
(150,3500,'Some item name 888', '9/19/2020')
The logic here is so that you can find new contact id each month (so logic is if same contact dont have any record in last 28 days from 1st of that month, it consider as new contact)
When you have two date periods, this is easy to do so you can exclude the records you want as below
SELECT *
FROM #SampleData
WHERE CreatedOn> = #FromDate
and CreatedOn <=#Date
and ContactId not in (SELECT ContactId
FROM #SampleData
WHERE CreatedOn >= DateAdd(Day, -28,#FromDate)
AND CreatedOn < #FromDate)
What I want is to pre-populate this data without having parameters to a some table so that user can use.
In this example data, I am expecting contact 3500 for July, 3000 for August and 2500&3000 for September.
Also it need to display only record per contact and not duplicate.
DECLARE #From date,
#To date
DECLARE date_cursor CURSOR FOR
select distinct DATEADD(month, DATEDIFF(month, 0, CreatedOn), 0) FromDate,EOMONTH(CreatedOn) ToDate
from #SampleData
OPEN date_cursor
FETCH NEXT FROM date_cursor INTO #From,#To
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT *
FROM (
SELECT DISTINCT ContactId,#From 'From Date', #To 'To Date'
FROM #SampleData D
WHERE D.CreatedOn>= #From AND D.CreatedOn <= #To
AND ContactId NOT IN (SELECT ContactId
FROM #SampleData
WHERE CreatedOn >= DateAdd(Day, -28,#From)
AND CreatedOn < #From)) ContactData
OUTER APPLY (
--pick first row for the contact as per the period
SELECT TOP 1 *
FROM #SampleData D
WHERE D.ContactId = ContactData.ContactId
AND D.CreatedOn >= ContactData.[From Date]
AND D.CreatedOn < ContactData.[To Date]
ORDER BY CreatedOn
) Records
FETCH NEXT FROM date_cursor INTO #From,#To
END
CLOSE date_cursor
DEALLOCATE date_cursor
Result
ContactId From Date To Date Id Item CreatedOn
3500 01/07/2020 31/07/2020 139 Some item name 6455 05/07/2020
3000 01/08/2020 31/08/2020 112 Some item name 5422 01/08/2020
2500 01/09/2020 30/09/2020 100 Some item name 1212 05/09/2020
3000 01/09/2020 30/09/2020 132 Some item name 344 05/09/2020
I would like to get rid of cursor, is there any possibility
You can assign a grouping to the contacts by using lag() and comparing the rows:
select sd.*,
sum(case when prev_createdon > dateadd(day, -28, createdon) then 0 else 1 end) over
(partition by contactid order by createdon) as grouping
from (select sd.*,
lag(createdon) over (partition by contactid order by createdon) as prev_createdon
from SampleData sd
) sd;
If you just want the first row in a series of adjacent records, then:
select sd.*
from (select sd.*,
lag(createdon) over (partition by contactid order by createdon) as prev_createdon
from SampleData sd
) sd
where prev_createdon < dateadd(day, -28, createdon) or prev_createdon is null;
Here is a db<>fiddle.
EDIT:
Based on the revised question, you want to summarize by group. You an do this using:
select contactid, min(createdon), max(createdon), min(id),
max(case when seqnum = 1 then item end) as item
from (select sd.*,
row_number() over (partition by contactid, grouping order by createdon) as seqnum
from (select sd.*,
sum(case when prev_createdon > dateadd(day, -28, createdon) then 0 else 1 end) over
(partition by contactid order by createdon) as grouping
from (select sd.*,
lag(createdon) over (partition by contactid order by createdon) as prev_createdon
from SampleData sd
) sd
) sd
) sd
group by contactid, grouping;
I updated the DB fiddle to have this as well.
I have a table TRANS that contains the following records:
TRANS_ID TRANS_DT QTY
1 01-Aug-2020 5
1 01-Aug-2020 1
1 03-Aug-2020 2
2 02-Aug-2020 1
The expected output:
TRANS_ID TRANS_DT BEGBAL TOTAL END_BAL
1 01-Aug-2020 0 6 6
1 02-Aug-2020 6 0 6
1 03-Aug-2020 6 2 8
2 01-Aug-2020 0 0 0
2 02-Aug-2020 0 1 1
2 03-Aug-2020 1 0 1
Each trans_id starts with a beginning balance of 0 (01-Aug-2020). For succeeding days, the beginning balance is the ending balance of the previous day and so on.
I can create PL/SQL block to create the output. Is it possible to get the output in 1 SQL statement?
Thanks.
Try this following script using CTE-
Demo Here
WITH CTE
AS
(
SELECT DISTINCT A.TRANS_ID,B.TRANS_DT
FROM your_table A
CROSS JOIN (SELECT DISTINCT TRANS_DT FROM your_table) B
),
CTE2
AS
(
SELECT C.TRANS_ID,C.TRANS_DT,SUM(D.QTY) QTY
FROM CTE C
LEFT JOIN your_table D
ON C.TRANS_ID = D.TRANS_ID
AND C.TRANS_DT = D.TRANS_DT
GROUP BY C.TRANS_ID,C.TRANS_DT
ORDER BY C.TRANS_ID,C.TRANS_DT
)
SELECT F.TRANS_ID,F.TRANS_DT,
(
SELECT COALESCE (SUM(QTY), 0) FROM CTE2 E
WHERE E.TRANS_ID = F.TRANS_ID AND E.TRANS_DT < F.TRANS_DT
) BEGBAL,
(
SELECT COALESCE (SUM(QTY), 0) FROM CTE2 E
WHERE E.TRANS_ID = F.TRANS_ID AND E.TRANS_DT = F.TRANS_DT
) TOTAL ,
(
SELECT COALESCE (SUM(QTY), 0) FROM CTE2 E
WHERE E.TRANS_ID = F.TRANS_ID AND E.TRANS_DT <= F.TRANS_DT
) END_BAL
FROM CTE2 F
You can as well do like this (I would assume it's a bit faster): Demo
with
dt_between as (
select mindt + level - 1 as trans_dt
from (select min(trans_dt) as mindt, max(trans_dt) as maxdt from t)
connect by level <= maxdt - mindt + 1
),
dt_for_trans_id as (
select *
from dt_between, (select distinct trans_id from t)
),
qty_change as (
select distinct trans_id, trans_dt,
sum(qty) over (partition by trans_id, trans_dt) as total,
sum(qty) over (partition by trans_id order by trans_dt) as end_bal
from t
right outer join dt_for_trans_id using (trans_id, trans_dt)
)
select
trans_id,
to_char(trans_dt, 'DD-Mon-YYYY') as trans_dt,
nvl(lag(end_bal) over (partition by trans_id order by trans_dt), 0) as beg_bal,
nvl(total, 0) as total,
nvl(end_bal, 0) as end_bal
from qty_change q
order by trans_id, trans_dt
dt_between returns all the days between min(trans_dt) and max(trans_dt) in your data.
dt_for_trans_id returns all these days for each trans_id in your data.
qty_change finds difference for each day (which is TOTAL in your example) and cumulative sum over all the days (which is END_BAL in your example).
The main select takes END_BAL from previous day and calls it BEG_BAL, it also does some formatting of final output.
First of all, you need to generate dates, then you need to aggregate your values by TRANS_DT, and then left join your aggregated data to dates. The easiest way to get required sums is to use analitic window functions:
with dates(dt) as ( -- generating dates between min(TRANS_DT) and max(TRANS_DT) from TRANS
select min(trans_dt) from trans
union all
select dt+1 from dates
where dt+1<=(select max(trans_dt) from trans)
)
,trans_agg as ( -- aggregating QTY in TRANS
select TRANS_ID,TRANS_DT,sum(QTY) as QTY
from trans
group by TRANS_ID,TRANS_DT
)
select -- using left join partition by to get data on daily basis for each trans_id:
dt,
trans_id,
nvl(sum(qty) over(partition by trans_id order by dates.dt range between unbounded preceding and 1 preceding),0) as BEGBAL,
nvl(qty,0) as TOTAL,
nvl(sum(qty) over(partition by trans_id order by dates.dt),0) as END_BAL
from dates
left join trans_agg tr
partition by (trans_id)
on tr.trans_dt=dates.dt;
Full example with sample data:
alter session set nls_date_format='dd-mon-yyyy';
with trans(TRANS_ID,TRANS_DT,QTY) as (
select 1,to_date('01-Aug-2020'), 5 from dual union all
select 1,to_date('01-Aug-2020'), 1 from dual union all
select 1,to_date('03-Aug-2020'), 2 from dual union all
select 2,to_date('02-Aug-2020'), 1 from dual
)
,dates(dt) as ( -- generating dates between min(TRANS_DT) and max(TRANS_DT) from TRANS
select min(trans_dt) from trans
union all
select dt+1 from dates
where dt+1<=(select max(trans_dt) from trans)
)
,trans_agg as ( -- aggregating QTY in TRANS
select TRANS_ID,TRANS_DT,sum(QTY) as QTY
from trans
group by TRANS_ID,TRANS_DT
)
select
dt,
trans_id,
nvl(sum(qty) over(partition by trans_id order by dates.dt range between unbounded preceding and 1 preceding),0) as BEGBAL,
nvl(qty,0) as TOTAL,
nvl(sum(qty) over(partition by trans_id order by dates.dt),0) as END_BAL
from dates
left join trans_agg tr
partition by (trans_id)
on tr.trans_dt=dates.dt;
You can use a recursive query to generate the overall date range, cross join it with the list of distinct tran_id, then bring the table with a left join. The last step is aggregation and window functions:
with all_dates (trans_dt, max_dt) as (
select min(trans_dt), max(trans_dt) from trans group by trans_id
union all
select trans_dt + interval '1' day, max_dt from all_dates where trans_dt < max_dt
)
select
i.trans_id,
d.trans_dt,
coalesce(sum(sum(t.qty)) over(partition by i.trans_id order by d.trans_dt), 0) - coalesce(sum(t.qty), 0) begbal,
coalesce(sum(t.qty), 0) total,
coalesce(sum(sum(t.qty)) over(partition by i.trans_id order by d.trans_dt), 0) endbal
from all_dates d
cross join (select distinct trans_id from trans) i
left join trans t on t.trans_id = i.trans_id and t.trans_dt = d.trans_dt
group by i.trans_id, d.trans_dt
order by i.trans_id, d.trans_dt
I have a table where I record daily work of employees. I have a query where I display the current work for today for each employee and have another query where I display the total count of work for each employee.
I want to combine the 2 queries into a single one where I have a daily column and a cumulative column.
my query is below:
SELECT staff,
process_inprogress,
not_yet_completed
FROM (SELECT staff,
Count(number) AS Process_InProgress,
Count(team_name) AS Not_Yet_Completed
FROM dbo.empty_shell_workflow
WHERE ( end_date IS NULL )
AND ( process_name IS NOT NULL )
AND ( billing_amount IS NULL )
AND ( deletion IS NULL )
AND ( team_name = 'Team Vishma' )
AND ( CONVERT(DATE, start_date) = CONVERT(DATE, Getdate()) )
GROUP BY staff
UNION ALL
SELECT staff,
Count(number) AS Process_InProgress,
Count(team_name) AS Not_Yet_Completed
FROM dbo.empty_shell_workflow AS Empty_Shell_Workflow_1
WHERE ( team_name = 'Team Vishma' )
AND ( billing_amount IS NULL )
AND ( tag_number IS NULL )
AND ( initiator IS NOT NULL )
AND ( end_date IS NULL )
AND ( deletion IS NULL )
AND ( process_name IS NOT NULL )
GROUP BY staff) AS t
however it is being display only in a single column for both daily and cumulative
Below is how i want it to display
Staff Process_Progress(Daily) Not_YetCompleted(Cumulative)
A 2 5
B 0 1
C 6 8
however from the query above, the cumulative is being display in the daily column
Any idea, how can I modify the query?
you could try like below by using case when
with cte as
( SELECT staff,CONVERT(DATE, start_date) as date_of_month
Count(number) AS Process_InProgress
FROM dbo.empty_shell_workflow AS Empty_Shell_Workflow_1
WHERE ( team_name = 'Team Vishma' )
AND ( billing_amount IS NULL )
AND ( tag_number IS NULL )
AND ( initiator IS NOT NULL )
AND ( end_date IS NULL )
AND ( deletion IS NULL )
AND ( process_name IS NOT NULL )
GROUP BY staff,CONVERT(DATE, start_date)
) select staff, sum(case when date_of_month = CONVERT(DATE, Getdate()) then
Process_InProgress else 0 end) as Process_Progress_Daily,
sum(case when date_of_month != CONVERT(DATE, Getdate()) then
Process_InProgress else 0 end) as Not_YetCompleted
from cte
group by staff
I have a table that has data like following.
attr |time
----------------|--------------------------
abc |2018-08-06 10:17:25.282546
def |2018-08-06 10:17:25.325676
pqr |2018-08-05 10:17:25.366823
abc |2018-08-06 10:17:25.407941
def |2018-08-05 10:17:25.449249
I want to group them and count by attr column row wise and also create additional columns in to show their counts per day and percentages as shown below.
attr |day1_count| day1_%| day2_count| day2_%
----------------|----------|-------|-----------|-------
abc |2 |66.6% | 0 | 0.0%
def |1 |33.3% | 1 | 50.0%
pqr |0 |0.0% | 1 | 50.0%
I'm able to display one count by using group by but unable to find out how to even seperate them to multiple columns. I tried to generate day1 percentage with
SELECT attr, count(attr), count(attr) / sum(sub.day1_count) * 100 as percentage from (
SELECT attr, count(*) as day1_count FROM my_table WHERE DATEPART(week, time) = DATEPART(day, GETDate()) GROUP BY attr) as sub
GROUP BY attr;
But this also is not giving me correct answer, I'm getting all zeroes for percentage and count as 1. Any help is appreciated. I'm trying to do this in Redshift which follows postgresql syntax.
Let's nail the logic before presenting:
with CTE1 as
(
select attr, DATEPART(day, time) as theday, count(*) as thecount
from MyTable
)
, CTE2 as
(
select theday, sum(thecount) as daytotal
from CTE1
group by theday
)
select t1.attr, t1.theday, t1.thecount, t1.thecount/t2.daytotal as percentofday
from CTE1 t1
inner join CTE2 t2
on t1.theday = t2.theday
From here you can pivot to create a day by day if you feel the need
I am trying to enhance the query #johnHC btw if you needs for 7days then you have to those days in case when
with CTE1 as
(
select attr, time::date as theday, count(*) as thecount
from t group by attr,time::date
)
, CTE2 as
(
select theday, sum(thecount) as daytotal
from CTE1
group by theday
)
,
CTE3 as
(
select t1.attr, EXTRACT(DOW FROM t1.theday) as day_nmbr,t1.theday, t1.thecount, t1.thecount/t2.daytotal as percentofday
from CTE1 t1
inner join CTE2 t2
on t1.theday = t2.theday
)
select CTE3.attr,
max(case when day_nmbr=0 then CTE3.thecount end) as day1Cnt,
max(case when day_nmbr=0 then percentofday end) as day1,
max(case when day_nmbr=1 then CTE3.thecount end) as day2Cnt,
max( case when day_nmbr=1 then percentofday end) day2
from CTE3 group by CTE3.attr
http://sqlfiddle.com/#!17/54ace/20
In case that you have only 2 days:
http://sqlfiddle.com/#!17/3bdad/3 (days descending as in your example from left to right)
http://sqlfiddle.com/#!17/3bdad/5 (days ascending)
The main idea is already mentioned in the other answers. Instead of joining the CTEs for calculating the values I am using window functions which is a bit shorter and more readable I think. The pivot is done the same way.
SELECT
attr,
COALESCE(max(count) FILTER (WHERE day_number = 0), 0) as day1_count, -- D
COALESCE(max(percent) FILTER (WHERE day_number = 0), 0) as day1_percent,
COALESCE(max(count) FILTER (WHERE day_number = 1), 0) as day2_count,
COALESCE(max(percent) FILTER (WHERE day_number = 1), 0) as day2_percent
/*
Add more days here
*/
FROM(
SELECT *, (count::float/count_per_day)::decimal(5, 2) as percent -- C
FROM (
SELECT DISTINCT
attr,
MAX(time::date) OVER () - time::date as day_number, -- B
count(*) OVER (partition by time::date, attr) as count, -- A
count(*) OVER (partition by time::date) as count_per_day
FROM test_table
)s
)s
GROUP BY attr
ORDER BY attr
A counting the rows per day and counting the rows per day AND attr
B for more readability I convert the date into numbers. Here I take the difference between current date of the row and the maximum date available in the table. So I get a counter from 0 (first day) up to n - 1 (last day)
C calculating the percentage and rounding
D pivot by filter the day numbers. The COALESCE avoids the NULL values and switched them into 0. To add more days you can multiply these columns.
Edit: Made the day counter more flexible for more days; new SQL Fiddle
Basically, I see this as conditional aggregation. But you need to get an enumerator for the date for the pivoting. So:
SELECT attr,
COUNT(*) FILTER (WHERE day_number = 1) as day1_count,
COUNT(*) FILTER (WHERE day_number = 1) / cnt as day1_percent,
COUNT(*) FILTER (WHERE day_number = 2) as day2_count,
COUNT(*) FILTER (WHERE day_number = 2) / cnt as day2_percent
FROM (SELECT attr,
DENSE_RANK() OVER (ORDER BY time::date DESC) as day_number,
1.0 * COUNT(*) OVER (PARTITION BY attr) as cnt
FROM test_table
) s
GROUP BY attr, cnt
ORDER BY attr;
Here is a SQL Fiddle.
Imagine we have a table:
SELECT SUM(A) AS TOTALS,DATE,STUFF FROM TABLE WHERE DATE BETWEEN 'DATESTART' AND 'DATEEND'
GROUP BY DATE,STUFF
Normally this gets the totals as:
totals stuff date
23 x 01.01.1900
3 x 02.01.1900
44 x 06.01.1900
But what if we have the previous the data before the startdate,and i want to add those initial data to my startdate value; for example; from the begining of time i already have a sum value of x lets say 100
so i want my table to start from 123 and add the previous data such as:
123
126
126+44 and so on...
totals stuff date
123 x 01.01.1900
126 x 02.01.1900
170 x 06.01.1900
How can i achieve that?
Source data:
WITH Stocks
AS (
SELECT
Dep.Dept_No ,
SUM(DSL.Metre) AS Metre ,
CONVERT(VARCHAR(10), Date, 112) AS Date
FROM
DS (NOLOCK) DSL
JOIN TBL_Depts (NOLOCK) Dep ON Dep.Dept_No = DSL.Dept
WHERE
1 = 1 AND
DSL.Sil = 0 AND
DSL.Depo IN ( 5000, 5001, 5002, 5003, 5004, 5014, 5018, 5021, 5101, 5109, 5303 ) AND
Dep.Dept_No NOT IN ( 6002 ) AND
Dep.Dept_No IN ( 6000, 6001, 6003, 6004, 6005, 6011, 6024, 6030 ) AND
DSL.Date BETWEEN '2013-06-19' AND '2013-06-20'
GROUP BY
Dep.Dept_No ,
CONVERT(VARCHAR(10), Date, 112)
)
SELECT
Stocks.Metre ,
Dep.Dept AS Dept ,
Stocks.Date
FROM
Stocks
LEFT JOIN TBL_Depts (NOLOCK) Dep ON Stocks.Dept = Dep.Dept
ORDER BY
Stocks.Metre DESC
Any RDBMS with window and analytic functions (SQL Server 2012, PostgreSQL but not MySQL)
SELECT
SumA + SUM(SumARange) OVER (ORDER BY aDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS TOTALS,
other, aDate
FROM
(
SELECT
SUM(a) AS SumARange,
other, aDate
FROM
SomeTable
WHERE
aDate BETWEEN '20130101' AND '20130106'
GROUP BY
other, aDate
) X
CROSS JOIN
(
SELECT
SUM(a) AS SumA
FROM
SomeTable
WHERE
aDate < '20130101'
) Y
ORDER BY
aDate;
or
SELECT
SUM(SumA) OVER () + SUM(SumARange) OVER (ORDER BY aDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS TOTALS,
other, aDate
FROM
(
SELECT
SUM(CASE WHEN aDate < '20130101' THEN a ELSE 0 END) AS SumA,
SUM(CASE WHEN aDate BETWEEN '20130101' AND '20130106' THEN a ELSE 0 END) AS SumARange,
other, aDate
FROM
SomeTable
WHERE
aDate <= '20130106'
GROUP BY
other, aDate
) X
ORDER BY
aDate;
SQLFiddle example and another
Use option with APPLY operator to calculate the totals. You need also add additional CASE expression in the GROUP BY clause
;WITH cte AS
(
SELECT SUM(a) AS sumA, [stuff], MAX([Date]) AS [Date]
FROM SomeTable
WHERE [Date] <= '20130106'
GROUP BY [stuff], CASE WHEN [Date] <= '20130101' THEN 1 ELSE [Date] END
)
SELECT o.total, [stuff], [Date]
FROM cte c CROSS APPLY (
SELECT SUM(c2.sumA) AS total
FROM cte c2
WHERE c.[Date] >= c2.[Date]
) o
See example on SQLFiddle