2013-02-13 20 views
2

想象一下,我想從[FormValues]獲得一個動態報告作爲數據,基於列的[ReportItems]作爲標題。TSQL從兩個表格創建一個動態報告,一個表格包含標題,另一個表格,數據

我真的很困惑如何做到這一點,並嘗試了很多方法,但沒有一個能正常工作。

我應該可以給一個[ReportID]過程並得到結果。

[FormID][FieldID]是兩個表之間的關係密鑰。

任何形式的幫助將不勝感激。

CREATE TABLE #ReportItems(
    ReportItemID [uniqueidentifier] NOT NULL primary key, 
    ReportID [uniqueidentifier] NOT NULL, 
    FormID [uniqueidentifier] NOT NULL, 
    FieldID [uniqueidentifier] NOT NULL, 
    Title nvarchar(100) NOT NULL 
) 
GO 

insert into #ReportItems 
select '5674d274-b146-4251-be0d-a15000e7cefa', '597d37c0-563b-42f0-99be-a15000dc7a65', '01304636-fabe-4a3e-9487-a14b012f9a61', 'ba6b9b1a-92ef-4905-830a-a15000d05f7a', 'First Name' 
insert into #ReportItems 
select '5674d274-b146-4252-be0d-a15000e7cefa', '597d37c0-563b-42f0-99be-a15000dc7a65', '01304636-fabe-4a3e-9487-a14b012f9a61', 'ba6b9b1a-92ef-4905-830a-a15000d05f7b', 'Last Name' 
insert into #ReportItems 
select '5674d274-b146-4253-be0d-a15000e7cefa', '597d37c0-563b-42f0-99be-a15000dc7a65', '01304636-fabe-4a3e-9487-a14b012f9a61', 'ba6b9b1a-92ef-4905-830a-a15000d05f7c', 'Age' 
GO 

CREATE TABLE #FormValues(
    ValueID uniqueidentifier NOT NULL primary key, 
    FormID uniqueidentifier NULL, 
    FieldID uniqueidentifier NOT NULL, 
    UserName nvarchar(100) NOT NULL, 
    Value nvarchar(max) null 
) 
GO 

insert into #FormValues 
select 'af6dc400-3972-49ff-9711-a1520002359e', '01304636-fabe-4a3e-9487-a14b012f9a61', 'ba6b9b1a-92ef-4905-830a-a15000d05f7a', 'user 1', 'Mike' 
insert into #FormValues 
select 'af6dc400-3972-49ff-9721-a1520002359e', '01304636-fabe-4a3e-9487-a14b012f9a61', 'ba6b9b1a-92ef-4905-830a-a15000d05f7b', 'user 1', 'Oscar' 
insert into #FormValues 
select 'af6dc400-3972-49ff-9731-a1520002359e', '01304636-fabe-4a3e-9487-a14b012f9a61', 'ba6b9b1a-92ef-4905-830a-a15000d05f7c', 'user 1', '20' 

insert into #FormValues 
select 'af6dc400-3972-49ff-9741-a1520002359e', '01304636-fabe-4a3e-9487-a14b012f9a61', 'ba6b9b1a-92ef-4905-830a-a15000d05f7a', 'user 2', 'Merry' 
insert into #FormValues 
select 'af6dc400-3972-49ff-9761-a1520002359e', '01304636-fabe-4a3e-9487-a14b012f9a61', 'ba6b9b1a-92ef-4905-830a-a15000d05f7c', 'user 2', '23' 

insert into #FormValues 
select 'af6dc400-3972-49ff-9771-a1520002359e', '01304636-fabe-4a3e-9487-a14b012f9a61', 'ba6b9b1a-92ef-4905-830a-a15000d05f7a', 'user 3', 'Alen' 
insert into #FormValues 
select 'af6dc400-3972-49ff-9781-a1520002359e', '01304636-fabe-4a3e-9487-a14b012f9a61', 'ba6b9b1a-92ef-4905-830a-a15000d05f7b', 'user 3', 'Escott' 
insert into #FormValues 
select 'af6dc400-3972-49ff-9791-a1520002359e', '01304636-fabe-4a3e-9487-a14b012f9a61', 'ba6b9b1a-92ef-4905-830a-a15000d05f7c', 'user 3', '28' 
GO 

Select * from #ReportItems 
Select * from #FormValues 
GO 

而且我想這樣的報告結果:

User Name | First Name | Last Name | Age 
User 1  | Mike  | Oscar  | 20 
User 2  | Merry  |    | 23 
User 3  | Alen  | Escott  | 28 
User n  | ...   | ...   | ... 



drop table #ReportItems 
drop table #FormValues 

回答

3

爲了得到你想要的結果,你將需要使用PIVOT功能。

如果所有的值(title)是已知的時間提前,那麼你可以硬編碼靜態查詢:

select * 
from 
(
    select r.Title, f.UserName, f.Value 
    from ReportItems r 
    left join FormValues f 
     on r.FormID = f.FormID 
     and r.FieldID = f.FieldID 
) src 
pivot 
(
    max(value) 
    for title in ([First Name], [Last Name], Age) 
) piv; 

SQL Fiddle with Demo

但它聽起來像你會有一個未知數titles,你想成爲列。如果是這樣的話,那麼你將要使用動態SQL:

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

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

set @query = 'SELECT UserName,' + @cols + ' from 
      (
       select r.Title, f.UserName, f.Value 
       from ReportItems r 
       left join FormValues f 
        on r.FormID = f.FormID 
        and r.FieldID = f.FieldID 
      ) x 
      pivot 
      (
       max(value) 
       for Title in (' + @cols + ') 
      ) p ' 

execute(@query) 

SQL Fiddle with Demo

兩個結果將是:

| USERNAME | FIRST NAME | LAST NAME | AGE | 
------------------------------------------- 
| user 1 |  Mike |  Oscar | 20 | 
| user 2 |  Merry | (null) | 23 | 
| user 3 |  Alen | Escott | 28 | 

如果你有一個特定的SortOrder你需要,並將其存儲在一個表中,那麼當您獲得列的列表時,將使用以下內容並按正確的順序返回列:

select @cols = STUFF((SELECT ',' + QUOTENAME(Title) 
        from ReportItems 
        group by Title, sortorder 
        order by sortorder 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

SQL Fiddle with Demo

+0

非常感謝您的完美答案。如果您不介意我需要另外兩個選項:1.如何通過[ReportID]請求結果2.如何按[ReportItems]中名爲[SortOrder]的列對標題進行排序? – Kardo 2013-02-13 16:47:48

+0

@Kardo你可以用額外的數據編輯sql小提琴嗎?當你編輯它時,在這裏發佈鏈接。或者用附加細節創建一個新問題。 – Taryn 2013-02-13 16:51:44

+0

其實你的答案是完美的,並且工作正常。我想對ReportItems中名爲[SortOrder]的列進行排序(例如:USERNAME | FIRST NAME | LAST NAME | AGE)。 – Kardo 2013-02-13 16:59:48

1
DECLARE @SQL NVARCHAR(MAX) 

SET @SQL='SELECT F.UserName' 
SELECT @SQL = @SQL+', MAX(CASE WHEN FieldID='''+CONVERT(VARCHAR(50), FieldID)+''' THEN F.Value END) AS ['+Title+'] 
' 
FROM #ReportItems 
SET @SQL = @SQL+' FROM #FormValues F GROUP BY F.UserName ORDER BY 1' 
--select @sql 
EXEC sp_ExecuteSQL @SQL 

後來編輯:根據報告ID的排序列

CREATE PROCEDURE spReport 
@ReportID uniqueidentifier, 
@SortColumns NVARCHAR(MAX) --shoud be a comma separated list of ReportItems.Title 
AS 
BEGIN 
    DECLARE @SQL NVARCHAR(MAX) 
    SET @SQL='SELECT F.UserName' 
    SELECT @SQL = @SQL+', MAX(CASE WHEN F.FieldID='''+CONVERT(VARCHAR(50), FieldID)+''' THEN F.Value END) AS ['+Title+'] 
    ' 
    FROM ReportItems 
    WHERE [email protected] --create the dynamic sql only for the items in your report 

    SET @SQL = @SQL+' FROM FormValues F 
    JOIN ReportItems R ON F.FormID=R.FormID 
    WHERE R.ReportID = @ReportID 
    GROUP BY F.UserName ' 
    IF @SortColumns<>'' 
     SET @SQL = @SQL + 'ORDER BY '[email protected] -- beware of SQL injection. 
    select @sql 
    EXEC sp_ExecuteSQL @SQL, N'@ReportID uniqueidentifier', @[email protected] 
END 

但是,我不能強調這一點的報告過程中,你必須要特別注意然後到@SortColumns參數,因爲你打開自己的SQL注入。

+0

Hi @Daniel,你的回答是正確的。現在我很困惑哪一個是更好的解決方案?很多再次感謝:) – Kardo 2013-02-13 16:55:12

+0

那麼,有一篇文章菲爾因素(在我的網站http://www.simple-talk.com上)認爲,CASE解決方案的表現要好於PIVOT。無論如何,這是你的電話。 – Daniel 2013-02-13 16:59:55

+0

其實,這篇文章是由Jeff Moden在SQLServerCentral上撰寫的http://www.sqlservercentral.com/articles/T-SQL/63681/ – Daniel 2013-02-13 17:05:45

相關問題