2 independent left join queries won't work together - sql

Ultimately I want my output to be a pivot query similar to below which I am comfortable doing
e.g.
Date CO RU ER AB
1/1/18 5 20 0 0
2/1/18 0 5 0 0
3/1/18 0 0 0 0
4/1/18 1 0 0 0
However, to get to that point I want to fill my data set with zero where no data exists
The table holds data similar to the following
Date/time Process_type Status
1/1/18 10:05 150 RU
2/1/18 14:00 150 CO
4/1/18 18:00 100 ER
On any given day there could be no processes.
I have written 2 queries whose purpose was to fill the gaps in the data. ie. fill days and statuses with zero counts where that combination does not exist.
This is a date range query that ensures zeroes are returned if the count is zero for dates where there is no info. This would give something similar to below
Date Count
1/1/18 25
2/1/18 5
3/1/18 0
4/1/18 1
This is a status query that ensures zeroes are returned if that zero is not status is not present
status count
AB 0
RU 2
CO 25
ER 0
I want to join the 2 queries so that I will get zeroes for both dates and status if the count is zero.
Date Status Count
1/1/18 AB 0
1/1/18 CO 0
1/1/18 ER 0
1/1/18 RU 0
2/1/18 AB 0
2/1/18 CO 6
3/1/18 ER 0
4/1/18 RU 1
When I join them up in Query 3 it wont run and gets the following error. I have tried a few different ways with no joy.
Error report -
SQL Error: ORA-00904: "TD"."TMP_DATE": invalid identifier
00000 - "%s: invalid identifier"
Query 1
--
-- Working out dates with nulls if zero count
--
with tmp_dates as (
select trunc(sysdate) - level + 1 as tmp_date
from dual
connect by level <= 5
)
select
count(pi.crtd_tstmp),
td.tmp_date
from
tmp_dates td
left join procedure_instance pi
on (td.tmp_date = trunc(pi.crtd_tstmp) and proc_oid = 150)
group by
td.tmp_date
order by
tmp_date;
Query 2
--
-- Working with Categories with zero if no category
--
with status_table as (
select 'CO' as instanceid from dual union
select 'RU' as instanceid from dual union
select 'ER' as instanceid from dual union
select 'AB' as instanceid from dual
)
select
count(pi.crtd_tstmp),
st.instanceid
from
status_table st
left join procedure_instance pi
on (st.instanceid = pi.stat and proc_oid = 150)
group by
st.instanceid
order by
st.instanceid;
Query 3
--
-- join together
--
with tmp_dates as (
select trunc(sysdate) - level + 1 as tmp_date
from dual
connect by level <= 5
),
status_table as (
select 'CO' as instanceid from dual union
select 'RU' as instanceid from dual union
select 'ER' as instanceid from dual union
select 'AB' as instanceid from dual
)
select
count(pi.crtd_tstmp),
td.tmp_date,
st.instanceid
from
tmp_dates td,
status_table st
left join procedure_instance pi
on (td.tmp_date = trunc(pi.crtd_tstmp) and proc_oid = 150)
left join procedure_instance pi
on (st.instanceid = pi.stat and proc_oid = 150)
group by
td.tmp_date,
st.instanceid
order by
tmp_date;

Maybe something like this with only one table in the from clause?
with tmp_dates as (
select trunc(sysdate) - level + 1 as tmp_date
from dual
connect by level <= 5
),status_table as (select 'CO' as instanceid from dual union
select 'RU' as instanceid from dual union
select 'ER' as instanceid from dual union
select 'AB' as instanceid from dual)
select count(pi.crtd_tstmp), td.tmp_date, st.instanceid
from tmp_dates td
left join procedure_instance pi on (td.tmp_date = trunc(pi.crtd_tstmp) and proc_oid = 150)
right join status_table st on (st.instanceid = pi.stat and proc_oid = 150)
group by td.tmp_date,st.instanceid
order by tmp_date;

I decided to get round this a different way, I used the pivot to fill the process statutes instead of using query 2 and the second join. Works exactly as wanted now.
select Process_created,
nvl(Complete, 0) as Complete,
nvl(Error, 0) as Error,
nvl(Running, 0) as Running,
nvl(Abort, 0) as Abort
from(
with tmp_dates as (
select trunc(sysdate) - level + 1 as tmp_date
from dual
connect by level <= 30
)
select
count(pi.crtd_tstmp) as number_of,
td.tmp_date as Process_created,
pi.stat as status
from
tmp_dates td
left join procedure_instance pi
on (td.tmp_date = trunc(pi.crtd_tstmp) and proc_oid = 150)
group by
td.tmp_date,pi.stat
order by
tmp_date)src
pivot(
sum(number_of)
for status in ('CO' as Complete, 'ER' as Error, 'RU' as Running, 'AB' as Abort )) piv order by process_created;

Try this and let me know what errors you get
--
-- join together
--
WITH tmp_dates
AS (
SELECT trunc(sysdate) - LEVEL + 1 AS tmp_date
FROM dual connect BY LEVEL <= 5
)
,status_table
AS (
SELECT 'CO' AS instanceid FROM dual
UNION
SELECT 'RU' AS instanceid FROM dual
UNION
SELECT 'ER' AS instanceid FROM dual
UNION
SELECT 'AB' AS instanceid FROM dual
)
SELECT count(pi.crtd_tstmp)
,td.tmp_date
,st.instanceid
FROM tmp_dates td
,status_table st
LEFT JOIN procedure_instance pi ON (
td.tmp_date = trunc(pi.crtd_tstmp)
AND proc_oid = 150
)
LEFT JOIN procedure_instance pi2 ON (
st.instanceid = pi2.stat
AND proc_oid = 150
)
GROUP BY td.tmp_date
,st.instanceid
ORDER BY td.tmp_date;

Related

query all of the same id based on multiple true conditions

I have this table :
id act st_dt end_dt stats
1 a 01/01/20 05/01/20 done
1 b 04/01/20 09/02/20 done
1 c 09/02/20 null not done
1 d 09/02/20 09/02/20 done
2 a 09/03/19 14/05/20 done
2 b 09/02/20 25/06/20 done
2 c 01/03/20 22/03/20 done
2 d 09/02/20 null not done
3 a 11/05/20 13/09/19 done
3 b 09/02/20 04/07/20 done
3 c 01/02/20 30/02/20 done
3 d 11/02/20 24/02/20 done
I want to query all activities 'act' of the same ID having activity a >= 01/01/20 and activity d status is done,
so the result should look like this:
id act st_dt end_dt stats
1 a 01/01/20 05/01/20 done
1 b 04/01/20 09/02/20 done
1 c 09/02/20 null not done
1 d 09/02/20 09/02/20 done
the two conditions are met for this id, i did this :
select * from
(
select
a.* ,
case when (act = 'a' and end_dt > to_date('01/01/20','dd/mm/yy')) and (act = 'd' and status = 'done') then 1 end) flag
from
table a
)
where flag = 1;
but it won't do the required,it'll query only activity 'a' and 'd'
You can use exists:
select a.*
from a
where exists (select 1
from a a2
where a2.id = a.id and a2.act = 'a' and a2.st_dt <= date '2020-01-01'
) and
exists (select 1
from a a2
where a2.id = a.id and a2.act = 'd' and a2.stats = 'done'
) ;
If you like to learn something new:
Creation of your table:
create table tab as
with t (id,act, start_date, end_date, status) as
(
select 1,'a',to_date('01/01/2020','dd/mm/yyyy'), to_date('05/01/2020','dd/mm/yyyy'), 'done' from dual union all
select 1,'b',to_date('04/01/2020','dd/mm/yyyy'), to_date('09/02/2020','dd/mm/yyyy'), 'done' from dual union all
select 1,'c',to_date('09/02/2020','dd/mm/yyyy'), null , 'not done' from dual union all
select 1,'d',to_date('09/02/2020','dd/mm/yyyy'), to_date('09/02/2020','dd/mm/yyyy'), 'done' from dual union all
select 2,'a',to_date('09/03/2019','dd/mm/yyyy'), to_date('14/05/2020','dd/mm/yyyy'), 'done' from dual union all
select 2,'b',to_date('09/02/2020','dd/mm/yyyy'), to_date('25/06/2020','dd/mm/yyyy'), 'done' from dual union all
select 2,'c',to_date('01/03/2020','dd/mm/yyyy'), to_date('22/03/2020','dd/mm/yyyy'), 'done' from dual union all
select 2,'d',to_date('09/02/2020','dd/mm/yyyy'), null , 'not done' from dual union all
select 3,'a',to_date('11/05/2020','dd/mm/yyyy'), to_date('13/09/2019','dd/mm/yyyy'), 'done' from dual union all
select 3,'b',to_date('09/02/2020','dd/mm/yyyy'), to_date('04/07/2020','dd/mm/yyyy'), 'done' from dual union all
select 3,'c',to_date('01/02/2020','dd/mm/yyyy'), to_date('29/02/2020','dd/mm/yyyy'), 'done' from dual union all --End_date is wrong in your input data I changed it to 29
select 3,'d',to_date('11/02/2020','dd/mm/yyyy'), to_date('24/02/2020','dd/mm/yyyy'), 'done' from dual
)
select * from t
Here is the solution that works on 12c and later
select * from tab
match_recognize
(
partition by id
order by start_date
all rows per match
pattern (a random_rows* d)
define a as act = 'a' and a.start_date >= date'2020-01-01',
d as act = 'd' and d.status = 'done'
);
One option would be using aggregated conditionals through an analytic function to determine whether both conditions are satisfied at the same time :
WITH a2 AS
(
SELECT a.*, SUM(CASE WHEN act = 'a' AND end_dt >= date'2020-01-01'
THEN 1
ELSE 0
END)
OVER(PARTITION BY id) *
SUM(CASE WHEN act = 'd' AND stats = 'done'
THEN 1
ELSE 0
END)
OVER(PARTITION BY id) AS satisfies
FROM a
)
SELECT id, act, st_dt, end_dt, stats
FROM a2
WHERE satisfies = 1
Demo
First get in two subqueries the ID of the well started and well done jobs.
INTERSECT the results to get jobs with both conditions and use this IDset in the IN predicate
Query
select *
from tab a
where id in (
select id
from tab a
where (act = 'a' and st_dt >= to_date('01/01/20','dd/mm/yy'))
INTERSECT
select id
from tab a
where (act = 'd' and stats = 'done')
)

How to transform and grouping in SQL

I would like to group bycontract date by transforming segment referring to its contract date like below.
contractdate segment
~2020/2/1 a
2020/2/2~2020/4/1 b
2020/4/2~ c
My desired result is to cut contractdate into segment and countthem into result tables.
If someone has opinion,please let me know.
Thanks
my table is like below.
contractdate status
2020/1/2 A
2020/4/2 B
2020/6/5 C
2020/1/2 C
2020/4/4 B
And here is my desired result.
segment A B C
a 1 0 1
b 0 0 0
c 0 2 1
Replace missing bounds with sentinels (or replace notation with weird tilde character at all), then distribute contractdate of statuses into proper ranges:
with sg (contractdate,segment) as (
select '~2020/2/1' , 'a' from dual union all
select '2020/2/2~2020/4/1', 'b' from dual union all
select '2020/4/2~' , 'c' from dual
), ssg as ( -- sanitized sg
select coalesce(to_date(regexp_replace(contractdate,'([^~]*)~([^~]*)','\1'),'YYYY/MM/DD'), date '-4712-1-1') as lowerbound -- source: https://laurentschneider.com/wordpress/2008/01/what-is-the-lowest-and-highest-possible-date-in-oracle.html
, coalesce(to_date(regexp_replace(contractdate,'([^~]*)~([^~]*)','\2'),'YYYY/MM/DD'), date '9999-01-01') as upperbound
, segment
from sg
), st (contractdate,status) as (
select '2020/1/2', 'A' from dual union all
select '2020/4/2', 'B' from dual union all
select '2020/6/5', 'C' from dual union all
select '2020/1/2', 'C' from dual union all
select '2020/4/4', 'B' from dual
)
select segment
, sum(case when status = 'A' then 1 else 0 end)
, sum(case when status = 'B' then 1 else 0 end)
, sum(case when status = 'C' then 1 else 0 end)
from ssg left join st on to_date(st.contractdate,'YYYY/MM/DD') between ssg.lowerbound and ssg.upperbound
group by segment
order by segment
Please use CTE to specify your input data, not plaintext tables. It helps to concentrate on answer instead of text formatting.

Join Many to One without a match

I'm not sure if the wording of my question is accurate but in short, I have 4 tables I need to access data from. DEPTH, DEPTHSET, DEPTHENTRY & DEPTHSETMM. I need my output to show 1 row per DEPTHSET, per DEPTH and I'm rolling up the data from DEPTHENTRY with a LISTAGG function. My problem is that I don't get a row for every DEPTH if there is not a valid DEPTHENTRY tied to it through the DEPTHSETMM many mapping table.
I've provided sample data through with clauses and then my actual code below that along with the current output and my desired output.
WITH
DEPTH AS (
(SELECT 1 AS "DEPTHID", 'Group' AS "NAME" FROM DUAL) UNION
(SELECT 2 AS "DEPTHID", 'Branch' AS "NAME" FROM DUAL) UNION
(SELECT 3 AS "DEPTHID", 'Area' AS "NAME" FROM DUAL) UNION
(SELECT 4 AS "DEPTHID", 'Dept' AS "NAME" FROM DUAL) UNION
(SELECT 5 AS "DEPTHID", 'Shift' AS "NAME" FROM DUAL) UNION
(SELECT 6 AS "DEPTHID", 'Rpt' AS "NAME" FROM DUAL) UNION
(SELECT 7 AS "DEPTHID", 'Code' AS "NAME" FROM DUAL)
),
DEPTHSET AS (
(SELECT 3705 AS "DEPTHSETID", 'Idaho Set' AS "NAME" FROM DUAL)
),
DEPTHSETMM AS (
(SELECT 3705 AS "DEPTHSETID", 1410 AS "ENTRYID" FROM DUAL) UNION
(SELECT 3705 AS "DEPTHSETID", 1420 AS "ENTRYID" FROM DUAL) UNION
(SELECT 3705 AS "DEPTHSETID", 1421 AS "ENTRYID" FROM DUAL) UNION
(SELECT 3705 AS "DEPTHSETID", 1430 AS "ENTRYID" FROM DUAL)
),
DEPTHENTRY AS (
(SELECT 1410 AS "ENTRYID", 'North West' AS "NAME", 1 AS "DEPTHID" FROM DUAL) UNION
(SELECT 1420 AS "ENTRYID", 'Zone 1' AS "NAME", 3 AS "DEPTHID" FROM DUAL) UNION
(SELECT 1421 AS "ENTRYID", 'Zone 2' AS "NAME", 3 AS "DEPTHID" FROM DUAL) UNION
(SELECT 1430 AS "ENTRYID", 'A' AS "NAME", 7 AS "DEPTHID" FROM DUAL)
)
SELECT
DST.name AS "DEPTH_SET_NAME",
DEP.depthid AS "DEPTHID",
DEP.name AS "DEPTH_NAME",
LISTAGG(CAST(DEE.name AS varchar2(2000)), '; ') WITHIN GROUP (ORDER BY DEE.name DESC) AS "ENTRY_NAME"
FROM DEPTHSETMM DMM
LEFT OUTER JOIN DEPTHENTRY DEE ON (DMM.entryid = DEE.entryid)
LEFT OUTER JOIN DEPTH DEP ON (DEE.depthid = DEP.depthid)
LEFT OUTER JOIN DEPTHSET DST ON (DMM.depthsetid = DST.depthsetid)
GROUP BY DST.name, DEP.depthid, DEP.name
ORDER BY DST.name, DEP.depthid
Current Output
DEPTH_SET_NAME DEPTHID DEPTH_NAME ENTRY_NAME
Idaho Set 1 Group North West
Idaho Set 3 Area Zone 2; Zone 1
Idaho Set 7 Code A
Desired Output
DEPTH_SET_NAME DEPTHID DEPTH_NAME ENTRY_NAME
Idaho Set 1 Group North West
Idaho Set 2 Branch NULL
Idaho Set 3 Area Zone 2; Zone 1
Idaho Set 4 Dept NULL
Idaho Set 5 Shift NULL
Idaho Set 6 Rpt NULL
Idaho Set 7 Code A
You can cross-join between DEPTHSET and DEPTH, and then outer-join to the remaining tables:
WITH ...
SELECT
DST.name AS "DEPTH_SET_NAME",
DEP.depthid AS "DEPTHID",
DEP.name AS "DEPTH_NAME",
LISTAGG(CAST(DEE.name AS varchar2(2000)), '; ') WITHIN GROUP (ORDER BY DEE.name DESC) AS "ENTRY_NAME"
FROM DEPTHSET DST
CROSS JOIN DEPTH DEP
LEFT OUTER JOIN DEPTHENTRY DEE ON (DEE.depthid = DEP.depthid)
LEFT OUTER JOIN DEPTHSETMM DMM ON (DMM.entryid = DEE.entryid)
AND (DMM.depthsetid = DST.depthsetid)
GROUP BY DST.name, DEP.depthid, DEP.name
ORDER BY DST.name, DEP.depthid;
DEPTH_SET DEPTHID DEPTH_ ENTRY_NAME
--------- ---------- ------ ------------------------------
Idaho Set 1 Group North West
Idaho Set 2 Branch
Idaho Set 3 Area Zone 2; Zone 1
Idaho Set 4 Dept
Idaho Set 5 Shift
Idaho Set 6 Rpt
Idaho Set 7 Code A
Notice the AND (DMM.depthsetid = DST.depthsetid) in the second outer join, replacing what used to be an indirect condition.

not a single-group group function using select case statement

I am writing below query which divides the two select query and calculate the percentage. But i am getting an error as not a single-group group function
select CASE WHEN COUNT(*) = 0 THEN 0 ELSE round((r.cnt / o.cnt)*100,3) END from
(Select count(*) as cnt from O2_CDR_HEADER WHERE STATUS NOT IN(0,1) and DATE_CREATED > (SYSDATE - 1)) r cross join
(Select count(*) as cnt from O2_CDR_HEADER WHERE DATE_CREATED > (SYSDATE - 1)) o;
You don't need to use joins. If I were you, I'd do:
select case when count(*) = 0 then 0
else round(100 * count(case when status not in (0, 1) then 1 end) / count(*), 3)
end non_0_or_1_status_percentage
from o2_cdr_header
where date_created > sysdate - 1;
Here's a simple demo:
with t as (select 1 status from dual union all
select 2 status from dual union all
select 3 status from dual union all
select 2 status from dual union all
select 4 status from dual union all
select 5 status from dual union all
select 6 status from dual union all
select 7 status from dual union all
select 1 status from dual union all
select 0 status from dual union all
select 1 status from dual)
select case when count(*) = 0 then 0
else round(100 * count(case when status not in (0, 1) then 1 end) / count(*), 3)
end col1
from t
where 1=0;
COL1
----------
0
And just in case you aren't sure that doing the filtering of the count in the case statement returns the same as when you filter in the where clause, here's a demo that proves it:
with t as (select 1 status from dual union all
select 2 status from dual union all
select 3 status from dual union all
select 2 status from dual union all
select 4 status from dual union all
select 5 status from dual union all
select 6 status from dual union all
select 7 status from dual union all
select 1 status from dual union all
select 0 status from dual union all
select 1 status from dual)
select 'using case statement' how_count_filtered,
count(case when status not in (0, 1) then 1 end) cnt
from t
union all
select 'using where clause' how_count_filtered,
count(*) cnt
from t
where status not in (0, 1);
HOW_COUNT_FILTERED CNT
-------------------- ----------
using case statement 7
using where clause 7
You are referencing an aggregate function (COUNT(*)) and an individual column expression (r.cnt and o.cnt) in the same SELECT query. This is not valid SQL unless a GROUP BY clause is added for the relevant individual columns.
It would be easier to provide a valid alternative it you could clarify what you'd like this query to return (given a sample schema and set of data). As a guess, I'd say you can simply substitute COUNT(*) with o.cnt to avoid the division by 0 issue. If there's some other logic expected to be present here, you'd need to clarify what that is.
It looks like you want to get a percentage of status not in 0,1, or 0 if there is no results.
Maybe this is what you want for the first line?
SELECT CASE WHEN (R.CNT = 0 AND O.CNT = 0) THEN 0 ELSE ROUND((R.CNT *100.0 / O.CNT),3) END
You don't need a cross join. Select the counts and do a division later on.
select case when ocnt > 0 then round((rcnt / ocnt)*100,3)
else 0 end
from
(
select
CASE WHEN STATUS NOT IN(0,1) and DATE_CREATED > (SYSDATE - 1)
THEN COUNT(*) END as rcnt,
CASE WHEN DATE_CREATED > (SYSDATE - 1)
THEN COUNT(*) END as ocnt
from O2_CDR_HEADER
group by status, date_created
) t
Boneist's answer is fine, but I would write it as:
select coalesce(round(100 * avg(case when status not in (0, 1) then 1.0 else 0
end), 3), 0) as non_0_or_1_status_percentage
from o2_cdr_header
where date_created > sysdate - 1;
Here is the answer which works perfectly for me
select CASE WHEN (o.cnt = 0) THEN 0 ELSE round((r.cnt / o.cnt)*100,3) END from
(Select count(*) as cnt from O2_CDR_HEADER WHERE STATUS NOT IN(0,1) and DATE_CREATED > (SYSDATE - 1)) r cross join
(Select count(*) as cnt from O2_CDR_HEADER WHERE DATE_CREATED > (SYSDATE - 1)) o

SQL query - sum of values by status for date interval

I get crazy because of one query. I have a table like following and I want to get a data - Summa of Values by Status For every Date in interval.
Table
Id Name Value Date Status
1 pro1 2 01.04.14 0
2 pro1 8 02.04.14 1
3 pro2 6 02.04.14 1
4 pro3 0 03.04.14 0
5 pro4 7 03.04.14 0
6 pro4 2 03.04.14 0
7 pro4 4 03.04.14 1
8 pro4 6 04.04.14 1
9 pro4 1 04.04.14 1
For example,
Input: Name = pro4, minDate = 01.02.14, maxDate = 04.09.14
Output:
Date Values sum for 0 Status Values sum for 1 Status
01.04.14 0 0
02.04.14 0 0
03.04.14 9 (=7+2) 4 (only 4 exist)
04.04.14 0 7 (6+1)
In 01.02.14 and 02.04.14 dates, pro4 has not values by status, but I want to show that rows, because I need all dates in that interval. Can anyone help me to create this query?
Edit:
I can not change structure, I have already that table with data. Every day exist in table many times (minimum 1 time)
Thanks in advance.
Assuming you have a row for each date in the table, use conditional aggregation:
select date,
sum(Case when name = 'pro4' and status = 0 then Value else 0 end) as values_0,
sum(case when name = 'pro4' and status = 1 then Value else 0 end) as values_1
from Table t
where date >= '2014-04-01' and date <= '2014-04-09'
group by date
order by date;
If you don't have this list of dates, you can take this approach instead:
with dates as (
select cast('2014-04-01' as date) as thedate
union all
select dateadd(day, 1, thedate)
from dates
where thedate < '2014-04-09'
)
select dates.thedate,
sum(Case when status = 0 then Value else 0 end) as values_0,
sum(case when status = 1 then Value else 0 end) as values_1
from dates left outer join
table t
on t.date = dates.thedate and t.name = 'pro4'
group by dates.thedate;
just an assumption query :
select Distinct date ,case when status = 0 and MAX(date) then SUM(value) ELSE 0 END Status0 ,
case when status = 1 and MAX(date) then SUM(value) ELSE 0 END Status1 from table
To expand my comment the complete query is
WITH [counter](N) AS
(SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1)
, days(N) AS (
SELECT row_number() over (ORDER BY (SELECT NULL)) FROM [counter])
, months (N) AS (
SELECT N - 1 FROM days WHERE N < 13)
, calendar ([date]) AS (
SELECT DISTINCT cast(dateadd(DAY, days.n
, dateadd(MONTH, months.n, '20131231')) AS date)
FROM months
CROSS JOIN days
)
SELECT a.Name
, c.Date
, [Sum of 0] = SUM(CASE Status WHEN 0 THEN Value ELSE 0 END)
, [Sum of 1] = SUM(CASE Status WHEN 1 THEN Value ELSE 0 END)
FROM Calendar c
LEFT JOIN myTable a ON c.Date = a.Date AND a.name = 'pro4'
WHERE c.date BETWEEN '20140201' AND '20140904'
GROUP BY c.Date, a.Name
ORDER BY c.Date
Note that the condition on the name need to be in the JOIN, otherwise you'll get only the date of your table.
If you need multiple years just add another CTE for the count and a dateadd(YEAR,...) in the CTE calendar
This is not really the exact query, but I think you can get that by having a query that looks like:
select date, status, sum(value) from table
where (date between mindate and maxdate) and name = product_name
group by date, status;
this page gives more info.
EDIT
So the above query only gives a part of the answer required by the OP. A LEFT OUTER JOIN of the original table and the result of the above query on thedate and status fields will give the missing info.
e.g.
select x.date, x.status, x.sum_of_values from table as y
left outer join
(select date, status, sum(value) as sum_of_values
from table
where (date between mindate and maxdate) and name = product_name
group by date, status) as x
on y.date= x.date and y.status = x.status
order by x.date;