2008-10-17 73 views
16

我正在处理一组类似于以下内容的数据。SQL Server 2005支持未知列数

StudentName | AssignmentName | Grade 
--------------------------------------- 
StudentA  | Assignment 1 | 100 
StudentA  | Assignment 2 | 80 
StudentA  | Total   | 180 
StudentB  | Assignment 1 | 100 
StudentB  | Assignment 2 | 80 
StudentB  | Assignment 3 | 100 
StudentB  | Total   | 280 

的名称和任务的数量是动态的,我需要得到的结果simlilar以下内容。

Student  | Assignment 1 | Assignment 2 | Assignment 3 | Total 
-------------------------------------------------------------------- 
Student A | 100   | 80   | null   | 180 
Student B | 100   | 80   | 100   | 280 

现在最好我想基于“到期日”可以列入/每个分配相关联的列进行排序。如果可能的话,总数应该在最后(如果可能的话,可以从查询中计算出来并且从查询中移除)。

我知道如何使用数据透视表来简单命名列的3个赋值,它正在尝试它以一种动态的方式,我还没有找到一个好的解决方案。我试图做到这一点的SQL Server 2005

编辑

在理想情况下,我想实现这一点没有使用动态SQL,因为这是违反政策的。如果这是不可能的...那么动态SQL的一个工作示例将起作用。

回答

11

我知道你说没有动态SQL,但我没有看到任何方式直接SQL

如果您在Pivot Table and Concatenate ColumnsPIVOT in sql 2005

动态SQL看看我的回答类似的问题没有容易注入,并没有很好的理由来禁止它。另一种可能性(如果数据很少发生变化)是执行代码生成 - 而不是动态的SQLSQL定期生成到存储过程。

+0

凯德伟大的例子看起来像我将不得不去那条路... – 2008-10-18 01:02:25

+0

感谢您的参考链接和示例!我只需要这样做,动态SQL似乎很脏,但有时需要 – 2008-10-18 01:26:35

+0

凯德,我只是想再次表示感谢!我有这样的工作就像现在在我身边的发条... – 2008-10-22 06:43:01

1

我发现要做到这一点的唯一方法是使用动态SQL并将列标签放入一个变量中。

0

您可以查询information_schema以获取列名称和类型,然后在生成结果集时将结果用作子查询。请注意,您可能需要稍微更改登录的访问权限。

+0

护理张贴了一个例子吗?我发现ws使用动态SQL建立列表的唯一方法,我宁愿不要 – 2008-10-17 20:30:51

+0

我不确定你能够摆脱动态SQL,因为PIVOT的IN子句必须具有硬编码值 - 在那里不允许再选择。哦,我真希望这不是真的! – BoltBait 2008-10-17 20:49:53

-2
select studentname,[Assign1],[Assign2],[Assign3],[Total] 
from 
(
select studentname, assignname, grade from student 
)s 
pivot(sum(Grade) for assignname IN([Assign1],[Assign2],[Assign3],[Total])) as pvt 
-1
SELECT TrnType 
INTO #Temp1 
FROM 
(
    SELECT '[' + CAST(TransactionType AS VARCHAR(4)) + ']' AS TrnType FROM tblPaymentTransactionTypes 
) AS tbl1 

SELECT * FROM #Temp1 

SELECT * FROM 
(
    SELECT FirstName + ' ' + LastName AS Patient, TransactionType, ISNULL(PostedAmount, 0) AS PostedAmount 
    FROM tblPaymentTransactions 
      INNER JOIN emr_PatientDetails ON tblPaymentTransactions.PracticeID = emr_PatientDetails.PracticeId 
      INNER JOIN tblPaymentTransactionDetails ON emr_PatientDetails.PatientId = tblPaymentTransactionDetails.PatientID 
         AND tblPaymentTransactions.TransactionID = tblPaymentTransactionDetails.TransactionID 
    WHERE emr_PatientDetails.PracticeID = 152 
) tbl 
PIVOT (SUM(PostedAmount) FOR [TransactionType] IN (SELECT * FROM #Temp1) 
) AS tbl4 
6

要使用动态SQL,你可以使用SQL Server 2005+下面的代码PIVOT这样的数据:

创建表:

CREATE TABLE yourtable 
    ([StudentName] varchar(8), [AssignmentName] varchar(12), [Grade] int) 
; 

INSERT INTO yourtable 
    ([StudentName], [AssignmentName], [Grade]) 
VALUES 
    ('StudentA', 'Assignment 1', 100), 
    ('StudentA', 'Assignment 2', 80), 
    ('StudentA', 'Total', 180), 
    ('StudentB', 'Assignment 1', 100), 
    ('StudentB', 'Assignment 2', 80), 
    ('StudentB', 'Assignment 3', 100), 
    ('StudentB', 'Total', 280) 
; 

动态PIVOT :

DECLARE @cols AS NVARCHAR(MAX), 
    @query AS NVARCHAR(MAX) 

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(AssignmentName) 
        from yourtable 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

set @query = 'SELECT StudentName, ' + @cols + ' from 
      (
       select StudentName, AssignmentName, grade 
       from yourtable 
      ) x 
      pivot 
      (
       min(grade) 
       for assignmentname in (' + @cols + ') 
      ) p ' 

execute(@query) 

SQL Fiddle with Demo

结果是:

| STUDENTNAME | ASSIGNMENT 1 | ASSIGNMENT 2 | ASSIGNMENT 3 | TOTAL | 
-------------------------------------------------------------------- 
| StudentA |   100 |   80 |  (null) | 180 | 
| StudentB |   100 |   80 |   100 | 280 |