Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
Author |
Topic |
Steve2106
Posting Yak Master
183 Posts |
Posted - 2011-03-24 : 12:53:27
|
Hi There,I need to show some statistics from a table. If we take the table layout to be:RecId + Responsible + Carer + Type 1 | 1 | 3 | Play 2 | 5 | 3 | Play 3 | 5 | 2 | Play 4 | 3 | 1 | Study 5 | 2 | 3 | Play 6 | 3 | 1 | Study 7 | 1 | 2 | Exercise 8 | 4 | 2 | Exercise 9 | 1 | 3 | Play I need to show, for a particular person say user 3, whose id is in either responsibe column or carer column, Total count of Records = 9 Responsible = 2 Carer = 4 And types Play 3Study 2Exercise 0Can that be done. Running through a table and calculating everything in 1 go?Thanks for your help.Best Regards,Steve |
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2011-03-24 : 13:38:40
|
It's not exactly the format you specified, but it does give you all the stats:DECLARE @t TABLE(RecId INT NOT NULL PRIMARY KEY, Responsible INT NOT NULL, Carer INT NOT NULL, TYPE VARCHAR(20) NOT NULL)INSERT @t SELECT 1,1,3,'Play' UNION ALL SELECT 2,5,3,'Play' UNION ALL SELECT 3,5,2,'Play' UNION ALL SELECT 4,3,1,'Study' UNION ALL SELECT 5,2,3,'Play' UNION ALL SELECT 6,3,1,'Study' UNION ALL SELECT 7,1,2,'Exercise' UNION ALL SELECT 8,4,2,'Exercise' UNION ALL SELECT 9,1,3,'Play';WITH CTE(Person, Side, TYPE) AS ( SELECT Person, Side, TYPE FROM (SELECT * FROM @t) a UNPIVOT (Person FOR Side IN(Responsible, Carer)) b),CTE2(Person, SideType) AS ( SELECT Person, Side FROM CTE UNION ALL SELECT Person, Type FROM CTE)SELECT Person, Responsible, Carer, Play, Study, Exercise FROM (select Person, SideType from CTE2) aPIVOT(Count(SideType) FOR SideType IN(Responsible, Carer, Play, Study, Exercise)) b The sections in red can be removed, and replace references to @t with your actual table name. |
 |
|
Seventhnight
Master Smack Fu Yak Hacker
2878 Posts |
Posted - 2011-03-24 : 13:43:27
|
how about:Declare @t Table ( RecId int, Responsible int, Carer int, Type varchar(10))Insert Into @t Select 1, 1, 3, 'Play' Insert Into @t Select 2, 5, 3, 'Play'Insert Into @t Select 3, 5, 2, 'Play'Insert Into @t Select 4, 3, 1, 'Study'Insert Into @t Select 5, 2, 3, 'Play'Insert Into @t Select 6, 3, 1, 'Study'Insert Into @t Select 7, 1, 2, 'Exercise'Insert Into @t Select 8, 4, 2, 'Exercise' Insert Into @t Select 9, 1, 3, 'Play' Select A.Person, Responsible = SUM(case when B.Responsible = A.Person then 1 else 0 end), Carer = SUM(case when B.Carer = A.Person then 1 else 0 end), Play = SUM(case when Type = 'Play' then 1 else 0 end), Study = SUM(Case when Type = 'Study' then 1 else 0 end), Exercise = SUM(case when Type = 'Exercise' then 1 else 0 end)From ( Select Person = Responsible From @t Union Select Person = Carer From @t ) AInner Join @t BOn A.Person = B.ResponsibleOr A.Person = B.CarerGroup By A.Person Corey snSQL on previous signature "...Oh and by the way Seventhnight, your signature is so wrong! On so many levels, morally, gramatically and there is a typo!" |
 |
|
Steve2106
Posting Yak Master
183 Posts |
Posted - 2011-03-25 : 05:16:23
|
Hi There,Thanks for the replies.They both work great but I can understand the one from Corey better.The stumbbleing block I have is that the example I gave is obviously fake and the type column holds an int that is related to the types table. In reality I need to get a count for all the Types in the types table.I could just create a: Play = SUM(case when Type = 'Play' then 1 else 0 end),For every type in the types table but then if someone adds a new type it will be broken. How can I loop through all the types and create a whatever = SUM(case when Type = 'whatever' then 1 else 0 end)Thanks very much for taking time to help it really is appreciated.Best Regards, Steve |
 |
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2011-03-27 : 16:50:37
|
http://www.sqlteam.com/article/dynamic-cross-tabs-pivot-tables |
 |
|
Steve2106
Posting Yak Master
183 Posts |
Posted - 2011-03-28 : 06:58:06
|
quote: Originally posted by robvolk http://www.sqlteam.com/article/dynamic-cross-tabs-pivot-tables
Hi There,Thanks for the reply.I keep getting an error when I try to create the Stored Procedure.Thanks for your help.Best Regards,Steve |
 |
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2011-03-28 : 07:07:10
|
If the error is "Syntax error near PIVOT", do a find-replace on "pivot" and change it to "_pivot". |
 |
|
Steve2106
Posting Yak Master
183 Posts |
Posted - 2011-03-28 : 08:46:39
|
quote: Originally posted by robvolk If the error is "Syntax error near PIVOT", do a find-replace on "pivot" and change it to "_pivot".
Hi There,Sorry to bother you again.There is @pivot ##pivot and pivotDo I just change the one that is pivot to _pivot?Thanks for your help,Steve |
 |
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2011-03-28 : 10:35:13
|
Better to change all of them. |
 |
|
Steve2106
Posting Yak Master
183 Posts |
Posted - 2011-03-28 : 10:59:03
|
quote: Originally posted by robvolk Better to change all of them.
Hi RobVolk,Really appreciate you trying to help but I still cannot get it to work.Have you tried creating the stored procedure and then running one of the EXECUTE crosstab queries from the link you provided.If you could try I would be greatful because then you will be able to see the trouble I am having.Best Regards,Steve |
 |
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2011-03-28 : 11:22:11
|
I made the code changes I specified and ran the following successfully:exec crosstab 'SELECT A.Person FROM (select Responsible Person from #t union select Carer from #t) AINNER JOIN #t B ON A.Person=B.Responsible OR A.Person=B.CarerGROUP BY A.Person', 'Count(A.Person)', 'Type', '#t' If you're getting an error, please post it. If you're not getting an error, then you'll have to elaborate on what's not working. |
 |
|
Steve2106
Posting Yak Master
183 Posts |
Posted - 2011-03-28 : 11:41:35
|
quote: Originally posted by robvolk I made the code changes I specified and ran the following successfully:exec crosstab 'SELECT A.Person FROM (select Responsible Person from #t union select Carer from #t) AINNER JOIN #t B ON A.Person=B.Responsible OR A.Person=B.CarerGROUP BY A.Person', 'Count(A.Person)', 'Type', '#t' If you're getting an error, please post it. If you're not getting an error, then you'll have to elaborate on what's not working.
Hi RobVolk,Thanks for sticking with me.This is my stored procedure:ALTER PROCEDURE [dbo].[crosstab] @select varchar(8000),@sumfunc varchar(100), @pivot varchar(100), @table varchar(100) ASDECLARE @sql varchar(8000), @delim varchar(1)SET NOCOUNT ONSET ANSI_WARNINGS OFFEXEC ('SELECT ' + @pivot + ' AS _pivot INTO _pivot FROM ' + @table + ' WHERE 1=2')EXEC ('INSERT INTO _pivot SELECT DISTINCT ' + @pivot + ' FROM ' + @table + ' WHERE ' + @pivot + ' Is Not Null')SELECT @sql='', @sumfunc=stuff(@sumfunc, len(@sumfunc), 1, ' END)' )SELECT @delim=CASE Sign( CharIndex('char', data_type)+CharIndex('date', data_type) ) WHEN 0 THEN '' ELSE '''' END FROM tempdb.information_schema.columns WHERE table_name='_pivot' AND column_name='_pivot'SELECT @sql=@sql + '''' + convert(varchar(100), _pivot) + ''' = ' + stuff(@sumfunc,charindex( '(', @sumfunc )+1, 0, ' CASE ' + @pivot + ' WHEN ' + @delim + convert(varchar(100), _pivot) + @delim + ' THEN ' ) + ', ' FROM _pivotDROP TABLE _pivotSELECT @sql=left(@sql, len(@sql)-1)SELECT @select=stuff(@select, charindex(' FROM ', @select)+1, 0, ', ' + @sql + ' ')EXEC (@select)SET ANSI_WARNINGS ONThis is what I have executed:exec crosstab 'SELECT A.Person FROM (select Responsible Person from #t union select Carer from #t) AINNER JOIN #t B ON A.Person=B.Responsible OR A.Person=B.CarerGROUP BY A.Person', 'Count(A.Person)', 'Type', '#t'These are the errors:Msg 208, Level 16, State 0, Line 1Invalid object name '#t'.Msg 208, Level 16, State 0, Line 1Invalid object name '#t'.Msg 208, Level 16, State 1, Procedure crosstab, Line 24Invalid object name '_pivot'.Thanks again for your help.If you could post the stored procedure you ran against I would appreciate it.Best Regards,Steve |
 |
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2011-03-28 : 11:51:09
|
Use this version:ALTER PROCEDURE crosstab @select varchar(8000),@sumfunc varchar(100), @_pivot varchar(100), @table varchar(100) ASDECLARE @sql varchar(8000), @delim varchar(1)SET NOCOUNT ONSET ANSI_WARNINGS OFFEXEC ('SELECT ' + @_pivot + ' AS _pivot INTO ##_pivot FROM ' + @table + ' WHERE 1=2')EXEC ('INSERT INTO ##_pivot SELECT DISTINCT ' + @_pivot + ' FROM ' + @table + ' WHERE ' + @_pivot + ' Is Not Null')SELECT @sql='', @sumfunc=stuff(@sumfunc, len(@sumfunc), 1, ' END)' )SELECT @delim=CASE Sign( CharIndex('char', data_type)+CharIndex('date', data_type) ) WHEN 0 THEN '' ELSE '''' END FROM tempdb.information_schema.columns WHERE table_name='##_pivot' AND column_name='_pivot'SELECT @sql=@sql + '''' + convert(varchar(100), _pivot) + ''' = ' + stuff(@sumfunc,charindex( '(', @sumfunc )+1, 0, ' CASE ' + @_pivot + ' WHEN ' + @delim + convert(varchar(100), _pivot) + @delim + ' THEN ' ) + ', ' FROM ##_pivotDROP TABLE ##_pivotSELECT @sql=left(@sql, len(@sql)-1)SELECT @select=stuff(@select, charindex(' FROM ', @select)+1, 0, ', ' + @sql + ' ')EXEC (@select)SET ANSI_WARNINGS ON |
 |
|
Steve2106
Posting Yak Master
183 Posts |
Posted - 2011-03-28 : 12:07:50
|
Hi RobVolk,That's great getting closer. That works with the Pubs Database but I cannot get it to work on my database with your latest execute code:exec crosstab 'SELECT A.Person FROM (select Responsible Person from #t union select Carer from #t) AINNER JOIN #t B ON A.Person=B.Responsible OR A.Person=B.CarerGROUP BY A.Person', 'Count(A.Person)', 'Type', '#t'I get errors:Msg 208, Level 16, State 0, Line 1Invalid object name '#t'.Msg 208, Level 16, State 0, Line 1Invalid object name '#t'.Msg 208, Level 16, State 1, Procedure crosstab, Line 26Invalid object name '##_pivot'.I appreciate you giving the stored procedure code. If I could just get there with this last bit would be fantastic.All the best,Steve |
 |
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2011-03-28 : 12:12:20
|
Sorry, I forgot to mention I used Seventhnight's code and changed it to a temp table from a table variable. Run this once before the crosstab:create Table #t( RecId int, Responsible int, Carer int, Type varchar(10))Insert Into #t Select 1, 1, 3, 'Play' Insert Into #t Select 2, 5, 3, 'Play'Insert Into #t Select 3, 5, 2, 'Play'Insert Into #t Select 4, 3, 1, 'Study'Insert Into #t Select 5, 2, 3, 'Play'Insert Into #t Select 6, 3, 1, 'Study'Insert Into #t Select 7, 1, 2, 'Exercise'Insert Into #t Select 8, 4, 2, 'Exercise' Insert Into #t Select 9, 1, 3, 'Play' Just change references for "#t" to your regular table name:exec crosstab 'SELECT A.Person FROM (select Responsible Person from myTable union select Carer from myTable) AINNER JOIN myTable B ON A.Person=B.Responsible OR A.Person=B.CarerGROUP BY A.Person', 'Count(A.Person)', 'Type', 'myTable' |
 |
|
Steve2106
Posting Yak Master
183 Posts |
Posted - 2011-03-28 : 12:29:39
|
Hi RobVolk,That's amazing and it works. Thankyou very much for taking the time to teach me this it really is appreciated.My only problem now is that the Type description is in a different table and I need to show these description as the column headers are 1,3,5,6,8 etc not really informative to the user.All the best,Steve. |
 |
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2011-03-28 : 13:02:36
|
Try something like this:exec crosstab 'SELECT A.Person FROM (select Responsible Person from myTable union select Carer from myTable) AINNER JOIN myTable B ON A.Person=B.Responsible OR A.Person=B.CarerINNER JOIN Types T ON B.Type=T.TypeGROUP BY A.Person', 'Count(A.Person)', 'T.TypeDescription', 'myTable' Change table/column names as needed. |
 |
|
Steve2106
Posting Yak Master
183 Posts |
Posted - 2011-03-28 : 13:30:24
|
Hi RobVolk,I am at home now so I'll have to try that tomorrow. I did get it sort of working by using a view but your way looks much better.Thanks for a great day, I mark it down as successfull thanks to all your help. I learnt a lot.Best Regards,Steve. |
 |
|
|
|
|
|
|