2016-08-16 22 views
1

我有两个数据表,我需要在一个SQL Server查询中连接在一起 - 一个包含事务信息,另一个包含已针对事务回答的市场营销问题。旋转未定义的文本列

这里是一个精简的例子:

------------------------------------------- 
|    Transaction Info    | 
|-------------------------------------------| 
|Transaction_ID |Date   |Customer_ID| 
|1    |2016-01-01 |2614  | 
|2    |2016-04-16 |3981  | 
|3    |2016-06-25 |2113  | 
------------------------------------------- 

------------------------------------------------------------------ 
|     Marketing Questions       | 
|------------------------------------------------------------------| 
|Transaction_ID |Question        |Answer  | 
|1    |How would you rate our service?  |Excellent | 
|2    |Would you recommend us?    |Yes  | 
|2    |Where did you hear about us?   |Friend  | 
|1    |Any other comments?     |None  | 
|3    |How would you rate our service?  |Average | 
|2    |Any other comments?     |None  | 
------------------------------------------------------------------ 

这里就是我坚持:我需要转动的营销表中的问题,成为列名在最后的连接表,在单元格的值是答案。

问题是,问题是从一个非常大的集合随机化的,所以我无法在查询中定义它们。它需要动态捕获表中返回的所有问题,将它们生成为列,然后在单元格中填充答案。

营销表本身就是日期范围查询的结果,因此包含的问题并不总是相同的。这就是为什么我不能提前将它们定义在PIVOT中的原因。

我真的不知道从哪里开始,所以任何帮助都非常感谢!

+3

哎哟...它看起来像您的MarketingQuestions严重需要正常化。一遍又一遍地重复提问并不是最好的设计。话虽如此,你试图完成的事情听起来像是一个动态的关键。这里已经有数百次和数百次的问答。 –

+0

我最近使用递归类做了一些事情。我需要在计算机上写下代码和测试,但是请稍等片刻 – Merenix

+0

如果应用程序最终是10%DBMS代码和90%支持代码,旨在解决DBMS功能中的缺陷,然后(a)选择不同的DBMS或(b)首先不使用DBMS。 DBMS旨在使任务更简单,而不是更复杂。如果不是,那么显然不合适,并且不适合当前的任务。 –

回答

0

您可以使用动态SQL轻松实现此目的。例如:

DECLARE @dynPiv varchar(max) 
DECLARE @PivotQuery 

SET @dynPiv = STUFF((SELECT ',' + QUOTENAME(Question) 
        FROM MarketingQuestions 
        FOR XML PATH(''), TYPE 
        ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'') 

SET @PivotQuery = '[YOUR QUERY HERE] 
PIVOT ([YOUR PIVOT GOES HERE] FOR Question IN ' + @dynPiv + ')' 

Didnt键入了整个代码,但应该共享这个想法。 @dynPiv将采用Question的所有不同值的值。打印@dynPiv以获得更好的可视化效果

0

再次,PIVOT是伟大的,但我使用存储过程的动态支点

不知道您想要的输出,但是你可以用参数播放/组通过的

Select A.* 
     ,B.Question 
     ,B.Answer 
Into #Temp 
From Transction A 
Join Marteting B 
    on (A.Transaction_ID=B.Transaction_ID) 

Exec [prc-Pivot] '#Temp','Question','max(Answer)[]','Customer_ID,Transaction_ID,Date','count(*)[Records]' 

返回

enter image description here

存储过程

CREATE PROCEDURE [dbo].[prc-Pivot] (
    @Source varchar(1000),   -- Any Table or Select Statement 
    @PvotCol varchar(250),   -- Field name or expression ie. Month(Date) 
    @Summaries varchar(250),  -- aggfunction(aggValue)[optionalTitle] 
    @GroupBy varchar(250),   -- Optional additional Group By 
    @OtherCols varchar(500))  -- Optional Group By or aggregates 
AS 

--Exec [prc-Pivot] 'Select Year=Year(TR_Date),* From [Chinrus-Series].[dbo].[DS_Treasury_Rates]','''Q''+DateName(QQ,TR_Date)','avg(TR_Y10)[-Avg]','Year','count(*)[Records],min(TR_Y10)[Min],max(TR_Y10)[Max],Avg(TR_Y10)[Avg]' 
--Exec [prc-Pivot] '#Temp','Attribute','max(Description)[]','ID','count(*)[Records]' 

Set NoCount On 
Set Ansi_Warnings Off 

Declare @Vals varchar(max),@SQL varchar(max); 
Set @Vals = '' 
Set @OtherCols= IsNull(', ' + @OtherCols,'') 
Set @Source = case when @Source Like 'Select%' then @Source else 'Select * From '[email protected] end 
Create Table #TempPvot (Pvot varchar(100)) 
Insert Into #TempPvot 
Exec ('Select Distinct Convert(varchar(100),' + @PvotCol + ') as Pvot FROM (' + @Source + ') A') 
Select @Vals = @Vals + ', isnull(' + Replace(Replace(@Summaries,'(','(CASE WHEN ' + @PvotCol + '=''' + Pvot + ''' THEN '),')[', ' END),0) As [' + Pvot) From #TempPvot Order by Pvot 
Drop Table #TempPvot 
Set @SQL = Replace('Select ' + Isnull(@GroupBy,'') + @OtherCols + @Vals + ' From (' + @Source + ') PvtFinal ' + case when Isnull(@GroupBy,'')<>'' then 'Group By ' + @GroupBy + ' Order by ' + @GroupBy else '' end,'Select , ','Select ') 
--Print @SQL 
Exec (@SQL) 


Set NoCount Off 
Set Ansi_Warnings on 
+0

我发誓我只是在另一篇文章上读到同样的东西大声笑 – Merenix

+0

@Merenix将它保留在我的剪贴板 –

+0

肯定。它是一个interstimg解决方案。尽管我有一个很快的问题,但假设我在一个只允许数据读取器访问的组织中工作。你推荐什么。到目前为止,我已经完成了ctes并且回转,但是通常我只是在办公桌前哭泣,希望问题消失 – Merenix