How to nest a join into a complicated Select sum(case, group by statement - sql

I am trying to generate a report, and so far have one completed that gives me how many orders, for each day, are in status 1-9.
TableA structure looks like this:
Sales Order | Order Status | Order Date
123456789 | 1 | 2017-02-22 00:00:00.000
123456790 | 0 | 2017-02-21 00:00:00.000
TableB structure looks like this:
Sales Order | Price
123456789 | 123.00
123456789 | 42.00
123456790 | 56.00
123456790 | 28.00
This code:
SELECT
MAX(year([OrderDate])) as Yr,
MAX(MONTH([OrderDate])) as M,
Day([OrderDate]) as Day,
sum(case when [OrderStatus]='0' THEN 1 ELSE 0 END) AS 'STATUS"0"',
sum(case when [OrderStatus]='1' THEN 1 ELSE 0 END) AS 'STATUS"1"',
sum(case when [OrderStatus]='2' THEN 1 ELSE 0 END) AS 'STATUS"2"',
sum(case when [OrderStatus]='4' THEN 1 ELSE 0 END) AS 'STATUS"4"',
sum(case when [OrderStatus]='8' THEN 1 ELSE 0 END) AS 'STATUS"8"',
sum(case when [OrderStatus]='9' THEN 1 ELSE 0 END) AS 'STATUS"9"',
sum(case when [OrderStatus]='S' THEN 1 ELSE 0 END) AS 'STATUS"S"',
sum(case when [OrderStatus]='*' THEN 1 ELSE 0 END) AS 'STATUS"*"',
sum(case when [OrderStatus]='/' THEN 1 ELSE 0 END) AS 'STATUS"/"'
FROM
SorMaster
WHERE
YEAR([OrderDate]) = YEAR(GETDATE())
GROUP BY
DATENAME(month, DateAdd(month, Month([OrderDate]) - 1, Cast('2008-01-01' AS Datetime))), Day([OrderDate])
ORDER BY
Yr DESC, M DESC, Day DESC
Returns this:
Yr | M | Day | STATUS"0" | STATUS"1" | STATUS"2" | STATUS"4" | STATUS"8" | STATUS"9" | STATUS"S" | STATUS"*" | STATUS"/"
2017 2 22 0 2 0 1 0 0 5 0 0
2017 2 21 0 0 0 7 0 0 0 0 0
This is PERFECT for my first report.
Now, comes the trouble. My Problem is that I need to nest-query Table B, so that instead of returning a count(orders), I need the sum(orders) those totals for each order are in Table B.
Using the above example, the query would need to return something like this:
Yr | M | Day | STATUS"0" | STATUS"1" | STATUS"2" | STATUS"4" | STATUS"8" | STATUS"9" | STATUS"S" | STATUS"*" | STATUS"/"
2017 2 22 0 165 0 0 0 0 0 0 0
2017 2 21 84 0 0 0 0 0 0 0 0
Any pointers?

Just join to TableB:
SELECT MAX(year([t1.OrderDate])) AS Yr,
MAX(MONTH([t2.OrderDate])) AS M,
DAY([t1.OrderDate]) AS Day,
SUM(CASE WHEN [OrderStatus] = '0' THEN t2.Price ELSE 0 END) AS 'STATUS"0"',
SUM(CASE WHEN [OrderStatus] = '1' THEN t2.Price ELSE 0 END) AS 'STATUS"1"',
SUM(CASE WHEN [OrderStatus] = '2' THEN t2.Price ELSE 0 END) AS 'STATUS"2"',
SUM(CASE WHEN [OrderStatus] = '4' THEN t2.Price ELSE 0 END) AS 'STATUS"4"',
SUM(CASE WHEN [OrderStatus] = '8' THEN t2.Price ELSE 0 END) AS 'STATUS"8"',
SUM(CASE WHEN [OrderStatus] = '9' THEN t2.Price ELSE 0 END) AS 'STATUS"9"',
SUM(CASE WHEN [OrderStatus] = 'S' THEN t2.Price ELSE 0 END) AS 'STATUS"S"',
SUM(CASE WHEN [OrderStatus] = '*' THEN t2.Price ELSE 0 END) AS 'STATUS"*"',
SUM(CASE WHEN [OrderStatus] = '/' THEN t2.Price ELSE 0 END) AS 'STATUS"/"'
FROM SorMaster t1
LEFT JOIN TableB t2
ON t1.[Sales Order] = t2.[Sales Order]
WHERE YEAR([OrderDate]) = YEAR(GETDATE())
GROUP BY DATENAME(month,DateAdd(month,Month([OrderDate])-1,Cast('2008-01-01' AS Datetime))),
DAY([OrderDate])
ORDER BY Yr DESC, M DEACLLSC, Day DESC

That's not too difficult, just a matter of LEFT JOINing in table B and then summing the prices in that. There's a couple of small tricks here. You want to LEFT JOIN to ensure that rows in table A always show up, even if there are no corresponding rows in table B. Secondly, in your SUM() statement, you'll need to add a COALESCE(...,0.00) to ensure you're summing decimals and no NULL values creep in from the LEFT JOIN. Oddly in databases, NULL + {anything} = NULL.
For the below query, you'll need to change the name of TableB to whatever the table name is, and the JOIN predicate will need to have the column names named accurately, and delimited correctly if they contain spaces. For example, in MSSQL the delimiters are [ and ], e.g. MyTable.[My Column With Spaces]
SELECT
MAX(YEAR([OrderDate])) as Yr,
MAX(MONTH([OrderDate])) as M,
DAY([OrderDate]) as Day,
sum(case when [OrderStatus]='0' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"0"',
sum(case when [OrderStatus]='1' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"1"',
sum(case when [OrderStatus]='2' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"2"',
sum(case when [OrderStatus]='4' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"4"',
sum(case when [OrderStatus]='8' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"8"',
sum(case when [OrderStatus]='9' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"9"',
sum(case when [OrderStatus]='S' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"S"',
sum(case when [OrderStatus]='*' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"*"',
sum(case when [OrderStatus]='/' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"/"'
FROM SorMaster
LEFT OUTER JOIN TableB
ON TableB.SalesOrder = SorMaster.SalesOrder
WHERE YEAR([OrderDate]) = YEAR(GETDATE())
GROUP BY
DATENAME(month,DateAdd(month,Month([OrderDate])-1,Cast('2008-01-01' AS Datetime))),
DAY([OrderDate])
ORDER BY
Yr DESC,
M DESC,
Day DESC

By (left) joining tableB and replacing your 'count' ones by tableB.price you should get the sum of all positions of orders with the according status.

Related

One select statement with multiple Group BY on the same column

I have 'TABLE_A' like this:
TVA Amount InvoiceID
----------------------
22 | 10.00 | inv-12
22 |-14.00 | inv-13
25 | 24.00 | inv-14
25 |-36.00 | inv-15
25 |-25.00 | inv-16
25 | 18.50 | inv-17
24 |-16.50 | inv-18
24 | 10.00 | inv-19
The goal is to make a groupBy TABLE_A.TVA value and by SUM(TABLE_A.Amount) > 0 and SUM(TABLE_A.Amount) <0, to get finally the sum of all positive Amounts grouped by TVA value, and the sum of all negative amounts grouped by their TVA value also
my Query is like this:
SELECT TABLE_A.TVA, TABLE_A.InvoiceID,
SUM(TABLE_A.Amount) AS [PositiveTotalAMount],
SUM(TABLE_A.Amount) AS [NegativeTotalAMount]
FROM TABLE_A
GROUP BY TABLE_A.TVA
HAVING SUM(TABLE_A.TVA) > 0
MY question is how to add the second grouping by on negative values, because here i group only on SUM() > 0
You can use a CASE (Transact-SQL) expression:
SELECT
A.TVA,
A.InvoiceID,
SUM(CASE WHEN A.Amount > 0 THEN A.Amount ELSE 0 END) AS [PositiveTotalAMount],
SUM(CASE WHEN A.Amount < 0 THEN A.Amount ELSE 0 END) AS [NegativeTotalAMount]
FROM
TABLE_A A
GROUP BY
A.TVA,
A.InvoiceID
Also, you must include all columns from the select list that are not aggregated to the GROUP BY list. InvoiceID was missing.
I also use the alias A for TABLE_A to increase readability.
With conditional aggregation:
SELECT
TABLE_A.TVA,
SUM(CASE WHEN TABLE_A.Amount > 0 THEN TABLE_A.Amount ELSE 0 END) AS [PositiveTotalAMount],
SUM(CASE WHEN TABLE_A.Amount < 0 THEN TABLE_A.Amount ELSE 0 END) AS [NegativeTotalAMount]
FROM TABLE_A
GROUP BY TABLE_A.TVA
If you want to include the column TABLE_A.InvoiceID in the grouping then:
SELECT
TABLE_A.TVA,
TABLE_A.InvoiceID,
SUM(CASE WHEN TABLE_A.Amount > 0 THEN TABLE_A.Amount ELSE 0 END) AS [PositiveTotalAMount],
SUM(CASE WHEN TABLE_A.Amount < 0 THEN TABLE_A.Amount ELSE 0 END) AS [NegativeTotalAMount]
FROM TABLE_A
GROUP BY TABLE_A.TVA, TABLE_A.InvoiceID

sql subquery that collects from 3 rows

I have a huge database with over 4 million rows that look like that:
Customer ID Shop
1 Asda
1 Sainsbury
1 Tesco
2 TEsco
2 Tesco
I need to count customers that within last 4 weeks had shopped in all 3 shops Tesco Sainsbury and Asda. Can you please advice if its possible to do it with subqueries?
This is an example of a "set-within-sets" subquery. You can solve it with aggregation:
select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) > 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0;
This structure is quite flexible. So if you wanted Asda and Tesco but not Sainsbury, then you would do:
select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) = 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0;
EDIT:
If you want a count, then use this as a subquery and count the results:
select count(*)
from (select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) > 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0
) t

Need Help on Oracle Select Query

I am finding difficulty to frame a select query.
PFB, for the table and corresponding data:
ID DLS MATCH_STATUS LAST_UPDATE_TIME BO CH FT
1 0 0 09-07-2013 00:00:00 IT TE NA
1 1 1 09-07-2013 00:01:01 IT TE NA
2 0 0 09-07-2013 10:00:00 IP TE NA
3 0 0 09-07-2013 11:00:00 IT YT NA
3 2 2 09-07-2013 11:01:00 IT YT NA
Here
Match_Status 0-->Initial Record
1-->Singel Match
2-->Multi Match
For every record there will be a initial entry with match_status 0 and subsequent matching process end other number such as 1,2 will be update.
I am trying to retrieve records such as total record , waiting match ,single match and multi match group by BO, CH and FT
Below is the expected out put:
BO CH FT TOTAL_RECORD AWAITNG_MATCH SINGLE_MATCH MULTI_MATCH
IT TE NA 1 0 1 0
IP TE NA 1 1 0 0
IT YT NA 1 0 0 2
I have tried below query :
select BO,CH,FT,sum(case when match_status=0 then 1 else 0 end) as TOTAL_RECORD,
sum(case when match_status = 0 then 1 else 0 end) as AWAITING_MATCH,
sum(case when match_status = 1 then 1 else 0 end) as SINGLE_MATCH,
sum(case when match_status = 2 then 1 else 0 end) as MULTI_MATCH from
table1 where last_update_time >= current_timestamp-1
group by BO,CH,FT;
problem with the above query is, awaiting_match is getting populated same as total record as I understand because of match_status=0
Similarly I tried with
select BO,CH,FT,sum(case when match_status=0 then 1 else 0 end) as TOTAL_RECORD,
select (sum(case when t1.ms=0 then 1 else 0 end) from
(select max(match_status) as ms from table1 where last_update_time >= current_timestamp-1 group by id)t1) )awaiting_match,
sum(case when match_status = 1 then 1 else 0 end) as SINGLE_MATCH,
sum(case when match_status = 2 then 1 else 0 end) as MULTI_MATCH from
table1 where last_update_time >= current_timestamp-1
group by BO,CH,FT;
problem with the approach is awaiting_match is getting populated with the same value for subsequent row entry.
Please help me with a suitable query for the desired format.
Thanks a lot in advance.
It seems that you want the last match status. I am guessing that this is actually the maximum of the statuses. If so, the following solves the problem by first grouping on id and then doing the grouping to summarize:
select BO, CH, FT,
count(*) as TOTAL_RECORD,
sum(case when lastms = 0 then 1 else 0 end) as AWAITING_MATCH,
sum(case when lastms = 1 then 1 else 0 end) as SINGLE_MATCH,
sum(case when lastms = 2 then 1 else 0 end) as MULTI_MATCH
from (select id, bo, ch, ft, MAX(match_status) as lastms
from table1
where last_update_time >= current_timestamp-1
group by id, bo, ch, ft
) t
group by BO, CH, FT;
If you actually want the last update to provide the status for the id, then you can use row_number() to enumerate the rows for each id, order by update time descending, and choose the first one:
select BO, CH, FT,
count(*) as TOTAL_RECORD,
sum(case when lastms = 0 then 1 else 0 end) as AWAITING_MATCH,
sum(case when lastms = 1 then 1 else 0 end) as SINGLE_MATCH,
sum(case when lastms = 2 then 1 else 0 end) as MULTI_MATCH
from (select id, bo, ch, ft, match_status,
ROW_NUMBER() over (partition by id order by last_update_time desc) as seqnum
from table1
where last_update_time >= current_timestamp-1
) t
where seqnum = 1
group by BO, CH, FT;

How To Accumulator All The Values

the output i would like to display was accumulator of total EMPL_NUM. For example, the value show in the field TOTAL_FEBRUARY=TOTAL_JANUARY+TOTAL_FEBRUARY,while for the value exist in field TOTAL_MARCH=TOTAL_MARCH+TOTAL_JANUARY+TOTAL_FEBRUARY. I hope some of you can provide the solution for do it. Thank you very much. The coding is show as below:
SELECT
(CASE WHEN To_Char(A.EFFDT,'MM')=01 THEN 1
WHEN To_Char(A.EFFDT,'MM')=02 THEN 2
WHEN To_Char(A.EFFDT,'MM')=03 THEN 3
WHEN To_Char(A.EFFDT,'MM')=04 THEN 4
WHEN To_Char(A.EFFDT,'MM')=05 THEN 5
WHEN To_Char(A.EFFDT,'MM')=06 THEN 6
WHEN To_Char(A.EFFDT,'MM')=07 THEN 7
WHEN To_Char(A.EFFDT,'MM')=08 THEN 8
WHEN To_Char(A.EFFDT,'MM')=09 THEN 9
WHEN To_Char(A.EFFDT,'MM')=10 THEN 10
WHEN To_Char(A.EFFDT,'MM')=11 THEN 11
WHEN To_Char(A.EFFDT,'MM')=12 THEN 12
ELSE NULL END) AS MONTHS
,Count(*) AS EMPL_NUM
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=01 THEN 1 ELSE 0 END) AS TOTAL_JANUARY
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=02 THEN 1 ELSE 0 END) AS TOTAL_FEBRUARY
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=03 THEN 1 ELSE 0 END) AS TOTAL_MARCH
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=04 THEN 1 ELSE 0 END) AS TOTAL_APRIL
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=05 THEN 1 ELSE 0 END) AS TOTAL_MAY
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=06 THEN 1 ELSE 0 END) AS TOTAL_JUN
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=07 THEN 1 ELSE 0 END) AS TOTAL_JULY
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=08 THEN 1 ELSE 0 END) AS TOTAL_AUGUST
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=09 THEN 1 ELSE 0 END) AS TOTAL_SEPTEMBER
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=10 THEN 1 ELSE 0 END) AS TOTAL_OCTOBER
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=11 THEN 1 ELSE 0 END) AS TOTAL_NOVEMBER
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=12 THEN 1 ELSE 0 END) AS TOTAL_DECEMBER
FROM PS_JOB A
,PS_CITIZEN_PSSPRT B
,PS_CITIZENSHIP C
,PS_CITIZEN_STS_TBL D
WHERE A.HR_STATUS='A'
AND A.EFFDT=(SELECT Max(A1.EFFDT) FROM PS_JOB A1 WHERE A.EMPLID=A1.EMPLID AND A.EMPL_RCD=A1.EMPL_RCD AND A1.EFFDT<=SYSDATE)
AND A.EMPL_RCD=0
AND A.EFFSEQ=(SELECT Max(A2.EFFSEQ) FROM PS_JOB A2 WHERE A.EMPLID=A2.EMPLID AND A.EMPL_RCD=A2.EMPL_RCD AND A.EFFDT=A2.EFFDT)
AND A.EMPLID =B.EMPLID(+)
AND B.DEPENDENT_ID=' '
AND A.EMPLID=C.EMPLID
AND B.EMPLID=C.EMPLID
AND B.DEPENDENT_ID=C.DEPENDENT_ID
AND B.COUNTRY=C.COUNTRY
AND B.COUNTRY=D.COUNTRY
AND C.COUNTRY=D.COUNTRY
AND C.CITIZENSHIP_STATUS=D.CITIZENSHIP_STATUS
AND C.CITIZENSHIP_STATUS IN ('5','7')
AND To_Char(A.EFFDT,'YYYY')=2012
GROUP BY CASE WHEN To_Char(A.EFFDT,'MM')=01 THEN 1
WHEN To_Char(A.EFFDT,'MM')=02 THEN 2
WHEN To_Char(A.EFFDT,'MM')=03 THEN 3
WHEN To_Char(A.EFFDT,'MM')=04 THEN 4
WHEN To_Char(A.EFFDT,'MM')=05 THEN 5
WHEN To_Char(A.EFFDT,'MM')=06 THEN 6
WHEN To_Char(A.EFFDT,'MM')=07 THEN 7
WHEN To_Char(A.EFFDT,'MM')=08 THEN 8
WHEN To_Char(A.EFFDT,'MM')=09 THEN 9
WHEN To_Char(A.EFFDT,'MM')=10 THEN 10
WHEN To_Char(A.EFFDT,'MM')=11 THEN 11
WHEN To_Char(A.EFFDT,'MM')=12 THEN 12
ELSE NULL END
nter code here
Use <= operator when calculating SUM, e.g.:
Sum(CASE WHEN TO_NUMBER(To_Char(A.EFFDT,'MM')) <= 3 THEN 1 ELSE 0 END) AS TOTAL_MARCH
I think what you are asking for is a running total. Take a look at analytic functions (for example, the psoug site). If the core of your query is correct, do a regular aggregate in the inner query, then wrap that in an analytic function for the running total.
SELECT month
,SUM(month_count) OVER ( ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW )
AS running_total
FROM ( SELECT To_Char(A.EFFDT,'MM') AS month
,COUNT(*) AS month_count
FROM PS_JOB A
,PS_CITIZEN_PSSPRT B
,PS_CITIZENSHIP C
,PS_CITIZEN_STS_TBL D
WHERE A.HR_STATUS='A'
AND A.EFFDT=( SELECT Max(A1.EFFDT)
FROM PS_JOB A1
WHERE A.EMPLID=A1.EMPLID
AND A.EMPL_RCD=A1.EMPL_RCD
AND A1.EFFDT<=SYSDATE )
AND A.EMPL_RCD=0
AND A.EFFSEQ=( SELECT Max(A2.EFFSEQ)
FROM PS_JOB A2
WHERE A.EMPLID=A2.EMPLID
AND A.EMPL_RCD=A2.EMPL_RCD
AND A.EFFDT=A2.EFFDT )
AND A.EMPLID =B.EMPLID(+)
AND B.DEPENDENT_ID=' '
AND A.EMPLID=C.EMPLID
AND B.EMPLID=C.EMPLID
AND B.DEPENDENT_ID=C.DEPENDENT_ID
AND B.COUNTRY=C.COUNTRY
AND B.COUNTRY=D.COUNTRY
AND C.COUNTRY=D.COUNTRY
AND C.CITIZENSHIP_STATUS=D.CITIZENSHIP_STATUS
AND C.CITIZENSHIP_STATUS IN ('5','7')
AND To_Char(A.EFFDT,'YYYY')=2012
GROUP BY To_Char(A.EFFDT,'MM')
)
ORDER BY month

GROUP BY WEEK with SQL

I have the following:
http://sqlfiddle.com/#!6/226ae/1
I'm trying to now add one row for each week of the year, and filter the contacts accordingly. CONTACTS has a datetime column. The new table will look like:
Status 1 Status 2 Status 3
Week 1 3 4 2
Week 2 1 5 3
Week 3 2 2 4
I think that DATEADD needs to be used, however I'm at a loss in terms of how to begin changing my query.
I do know that MySQL has a GROUP BY WEEK command, but I don't think that SQL has an equivalent. What's the best way to accomplish this?
You can use DATEPART(), this groups by both the week and the year in the event you have data spanning multiple years:
SELECT
'Week ' + cast(datepart(wk, created) as varchar(2)) Week,
SUM(case WHEN status = 1 then 1 else 0 end) Status1,
SUM(case WHEN status = 2 then 1 else 0 end) Status2,
SUM(case WHEN status = 3 then 1 else 0 end) Status3,
SUM(case WHEN status = 4 then 1 else 0 end) Status4,
SUM(case WHEN status = 5 then 1 else 0 end) Status5
FROM contacts
group by datepart(wk, created), year(created)
See SQL Fiddle with Demo
Adding the year to the final result:
SELECT
'Week ' + cast(datepart(wk, created) as varchar(2)) Week,
year(created) year,
SUM(case WHEN status = 1 then 1 else 0 end) Status1,
SUM(case WHEN status = 2 then 1 else 0 end) Status2,
SUM(case WHEN status = 3 then 1 else 0 end) Status3,
SUM(case WHEN status = 4 then 1 else 0 end) Status4,
SUM(case WHEN status = 5 then 1 else 0 end) Status5
FROM contacts
group by datepart(wk, created), year(created)
See SQL Fiddle with demo
You can use the datepart function to extract the week from a date.
The query becomes:
SELECT datepart(week, created) as week,
SUM(case WHEN status = 1 then 1 else 0 end) Status1,
SUM(case WHEN status = 2 then 1 else 0 end) Status2,
SUM(case WHEN status = 3 then 1 else 0 end) Status3,
SUM(case WHEN status = 4 then 1 else 0 end) Status4,
SUM(case WHEN status = 5 then 1 else 0 end) Status5
FROM contacts
group by datepart(week, created)
SqlFiddle: http://sqlfiddle.com/#!6/226ae/6tsq
You might try using the group by clause in your query:
SELECT
DATE_FORMAT( created, '%u' ) week_number,
SUM(case WHEN status = 1 then 1 else 0 end) Status1,
SUM(case WHEN status = 2 then 1 else 0 end) Status2,
SUM(case WHEN status = 3 then 1 else 0 end) Status3,
SUM(case WHEN status = 4 then 1 else 0 end) Status4,
SUM(case WHEN status = 5 then 1 else 0 end) Status5
FROM contacts
GROUP BY DATE_FORMAT( created, '%u' )
I'm assuming you are talking about mysql.
The DATE_FORMAT function is documented here:
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-format