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.

 All Forums
 SQL Server 2000 Forums
 Transact-SQL (2000)
 Pivot from one table

Author  Topic 

SubCreator
Starting Member

8 Posts

Posted - 2004-06-28 : 04:41:06
Hi

I have one table containing studentID, ExamCode and Grade.

I would of course view this table as a pivot.

But I just get error messages. How would you (people who know this by heart) write that procedure call?


--
SubCreator

tkizer
Almighty SQL Goddess

38200 Posts

Posted - 2004-06-28 : 13:59:38
What are your error messages? Please post your code.

Tara
Go to Top of Page

fjorner
Starting Member

5 Posts

Posted - 2004-06-28 : 17:11:26
I assume you've taken a look at http://www.sqlteam.com/item.asp?ItemID=2955 already?
Go to Top of Page

kselvia
Aged Yak Warrior

526 Posts

Posted - 2004-06-29 : 00:33:50
Read the article above. Essentialy this:

DECLARE @sql varchar(8000)
SELECT @sql = COALESCE(@sql + ',', 'select studentID, ') + replace('[~] = sum(case when ExamCode=~ then Grade else 0 end)','~',ExamCode)
FROM (select distinct ExamCode from mytable) x
SET @sql = @sql + ' from mytable group by studentID'
EXEC (@sql)

Go to Top of Page

SubCreator
Starting Member

8 Posts

Posted - 2004-06-29 : 03:31:11
Of course I've read the article, and the discussion related to it. I'm basically stupid :)
:)

My table has these fields:
School
Study
StudentID
ExamCode
Grade

I would (optimally) like to have the following output:

School | Study | Studentid | Examcode1 | Examcode n...
-----------------------------------------------------------
MySchool | MyStudy | 1234 | B+ | C- ...
etc...

Anyone?

I run an SQL Server 2000, and the table is pretty big.
Which of the crosstab scripts should I use, in your opinion? (I registrered that a lot of improvement has been made to the original script.



--
SubCreator
Go to Top of Page

kselvia
Aged Yak Warrior

526 Posts

Posted - 2004-06-29 : 03:53:53
The code I posted should do that if you add School and Study like so:

DECLARE @sql varchar(8000)
SELECT @sql = COALESCE(@sql + ',', 'select School, Study, Studentid, ') + replace('[~] = sum(case when ExamCode=~ then Grade else 0 end)','~',ExamCode)
FROM (select distinct ExamCode from mytable) x
SET @sql = @sql + ' from mytable group by School, Study, Studentid'
EXEC (@sql)

I have also used this version and it worked well for me. [url]http://www.experts-exchange.com/Databases/Microsoft_SQL_Server/Q_20333808.html[/url]

Run it with:

exec sp_crosstab @tablename = N'MyTable', @crosscolumn = N'StudentID', @crossrow = N'ExamCode', @crossvalue = N'Grade', @where = N'WHERE MySchool=''someschool'''

But it will not include School and Study in the output. Maybe one of the other versions will, but the dynamic SQL I showed above should also work.

It has a limit on the number of columns and size of the dynamic SQL you can build. This version is supposed to support 700+ columns, but I have not used it: [url]http://www.developersdex.com/gurus/code/826.asp[/url]


CREATE procedure sp_CrossTab
@tablename varchar(255), -- Table/View on which to perform the cross tab query.
@crosscolumn varchar(255), -- Attribute to be used as columns in the cross tab.
@crossrow varchar(255), -- Attribute to be used as rows in the cross tab.
@crossvalue varchar(255) -- Attribute to be used as value in the cross tab.
As

-- Work variables
declare
@sql varchar(8000), -- Hold the dynamically created sql statement
@colname varchar(255), -- The current column when building sql statement
@i smallint, -- know when we reached the last column (@i = @cols)
@cols smallint, -- Number of columns
@longest_col smallint, -- the len() of the widest column
@CrLf char(2)
-- Constants
declare
@max_cols_in_table smallint,
@max_col_name_len smallint,
@max_statement_len smallint,
-- @sql7 bit, -- 1 when version 7, 0 otherwise.
@err_severity int

set nocount on

set @max_cols_in_table = 255
set @max_statement_len = 8000
set @max_col_name_len = 128
set @err_severity = 11
set @CrLf = char(13) + char(10)


-- Check inputs
if @tablename is null or @crosscolumn is null or @crossrow is null or @crossvalue is null begin
raiserror ('Missing parameter(s)!',@err_severity,1)
return 0
end

-- Check for existence of the table.
if (not exists(select * from sysobjects where name like @tablename))begin
raiserror ('Table/View for crosstab not found!',@err_severity,1)
return 0
end

-- Don't check for columns because we may actually get an expression as the column name

-- prepare for future feature of checking database version to validate
-- inputs. Default to version 7
--set @sql7 = 1
--if (patindex('%SQL Server 7.%',@@version) = 0) begin
-- set @sql7 = 0
--end

-- Extract all values from the rows of the attribute
-- we want to use to create the cross column. This table
-- will contain one row for each column in the crosstab.
create table #crosscol (crosscolumn varchar(255))
set @sql = ' insert #crosscol Select Distinct ' + @crosscolumn +
' From ' + @tablename --+
--' Group By ' + @crosscolumn
--print @sql
exec (@sql)
set @cols = @@rowcount

if @cols > @max_cols_in_table begin
raiserror ('Exceeded maximum number of columns in Cross-tab',@err_severity,1)
return 0
end
else begin
if @cols = 0 begin
raiserror ('Could not find values to use for columns in Cross-tab',@err_severity,1)
return 0
end
else begin
-- Check if any of the data is too long to make it a name of a column
select @longest_col = max(len(convert(varchar(129),crosscolumn)))
from #crosscol

if @longest_col > @max_col_name_len begin
raiserror ('Value for column name exceeds legal length of column names',@err_severity,1)
return 0
end
else begin

-- All Validations OK, start building the dynamic sql statement

set @sql = ''
-- Use tmp table rows to create the sql statement for the crosstab.
-- each row in the table will be a column in the cross-tab
set @sql = 'select isnull(convert(varchar(255), ' + @crossrow + '),''Undefined'') As '
+ @crossrow + ', ' + @CrLf + space(4)

--set @sql = 'select ' + @crossrow + ', ' + char(13)

declare cross_sql cursor for
select crosscolumn
from #crosscol
order by crosscolumn

--print 'Sql cross statment: ' + @sql

open cross_sql
fetch next from cross_sql into @colname
-- Use "@i" to check for the last column. We need to input commas
-- between columns, but not after the last column
set @i = 0
while @@FETCH_STATUS = 0 begin
set @i = @i + 1
set @colname = isnull(@colname,'Undefined')
set @crossvalue = isnull(@crossvalue, 0)

Set @sql = @sql + '''' +
convert(varchar(128), @colname) +
''' = sum(case convert(varchar(128), ' + @crosscolumn + ')'
+ char(13) + char(10) + space(8) +
' when ''' + @colname + ''' then ' + @crossvalue + ' else 0 end) '

if @i < @cols
set @sql = @sql + ', ' + @CrLf + space(4)
else
set @sql = @sql + @CrLf

fetch next from cross_sql into @colname
end

close cross_sql
deallocate cross_sql

set @sql = @sql + ' from ' + @tablename + ' Group By ' + @crossrow

if len(@sql) >= @max_statement_len begin
raiserror ('Crosstab sql statement cannot exceed 7999 characters',@err_severity,1)
return 0
end

exec (@sql)
Select 'Sql' = @sql
set nocount off
return 1

end
end
end

GO
Go to Top of Page

SubCreator
Starting Member

8 Posts

Posted - 2004-06-29 : 05:05:35
Thanks. I didn't quite understand that you had made another script doing the same thing, and actually make it so small.

I tried you script, but got these message back.
(I'm not into SQL Scripting, just to say that!)

The examcode is alphanumeric, and so is the grades, actually. Basicly, all fields are alphanumeric.

Server: Msg 207, Level 16, State 3, Line 1
Invalid column name 'MSAFP'.
Server: Msg 207, Level 16, State 1, Line 1
Invalid column name 'MSEPPF'.
Server: Msg 207, Level 16, State 1, Line 1
Invalid column name 'MSTER'.
Stored Procedure: studentservice.dbo.sp_Karakterer
Return Code = 0

--
SubCreator
Go to Top of Page

kselvia
Aged Yak Warrior

526 Posts

Posted - 2004-06-29 : 19:41:56
Please post the query you tried to run.
Go to Top of Page

SubCreator
Starting Member

8 Posts

Posted - 2004-06-30 : 03:24:31
I made it!

DECLARE @sql varchar(8000)
SELECT @sql = COALESCE(@sql + ',', 'select School, Study, Studentid, ') + replace('[~] = Min(case when ExamCode=''~'' then Grade else NULL end)','~',ExamCode)
FROM (select distinct ExamCode from KAR) x
SET @sql = @sql + ' from KAR group by School, Study, Studentid'
exec (@sql)
GO


I had to change the grade to a vchar, and the else-value to NULL, and put the fields ExamCode in the group clause.


--
SubCreator
Go to Top of Page

kselvia
Aged Yak Warrior

526 Posts

Posted - 2004-06-30 : 12:08:17
Glad to help.
Go to Top of Page
   

- Advertisement -