SQL Server - 有条件地转置数据

时间:2016-11-23 07:36:26

标签: sql-server pivot pivot-table user-defined-functions transpose

我有一个数据集,如下图所示: Original dataset

我需要构建如下报告: Report needed

基本上每个人在PersonLang表中都有一些条目。条目表示每个语言 - 技能组合的一行加上该级别。

报告应包含一个人知道的所有语言,按照分数的顺序(级别)按列顺序排序。先进先出,然后是中等等。

到目前为止,我已尝试过几件事:

  1. 我尝试使用PIVOT,但我事先并不知道一个人的所有语言,如果一个人只知道它应该出现在第一列中,那么
  2. 我尝试使用由personid分区并按语言级别排序的窗口函数(Lead)。在这里,我遇到了问题,因为每种语言都需要一行而不是所有技能
  3. 我正在考虑编写一个表值函数,它将原始数据集作为游标,然后在所需的表中进行转换。在这里我遇到了在同一行插入所有值的问题,如果一个langugage出现两次同一级别,我应该只更新级别。
  4. 我想我会以某种方式过度思考这个问题,也许有更清晰思想的人可以指出我正确的解决方案。应该对原始数据集应用什么才能获得所需的结果?

    复制数据的SQL语句:

    var page = require('webpage').create();
    var websiteAddress = 'http://poe.ninja/standard/currency';
    page.settings.userAgent = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36';
    //viewportSize being the actual size of the headless browser
    page.viewportSize = { width: 1920, height: 1080 };
    //the clipRect is the portion of the page you are taking a screenshot of
    page.clipRect = { top: 0, left: 0, width: 1920, height: 1080 };
    
    page.open(websiteAddress, function (status) {
        setTimeout(function(){
            page.render('output.png');
            phantom.exit();
        }, 5000); // 5 sec should be enough
    });
    

    提前致谢

1 个答案:

答案 0 :(得分:0)

     DECLARE @sql NVARCHAR(max),@col NVARCHAR(max)

     SELECT @col=ISNULL(@col+',','')+'[ForeignLand'+n.LangID+'],[ForeignLand'+n.LangID+'Spoken],['+'ForeignLand'+n.LangID+'Written]'
     FROM (
       SELECT DISTINCT CONVERT(VARCHAR,DENSE_RANK()OVER(PARTITION BY personid ORDER BY lang)) AS LangID
       FROM personlang 
     ) n
     PRINT @col
     SELECT @sql='
     SELECT * FROM (
         SELECT l.personid,c.* FROM (
           SELECT *, DENSE_RANK()OVER(PARTITION BY pl.personid ORDER BY lang) AS LangID FROM personlang AS pl
         ) l
         CROSS APPLY (VALUES(''ForeignLand''+CONVERT(VARCHAR,LangID),lang)
                           ,(''ForeignLand''+CONVERT(VARCHAR,LangID)+''Spoken'',CASE WHEN langskill=''Spoken'' THEN lvl ELSE NULL END )
                           ,(''ForeignLand''+CONVERT(VARCHAR,LangID)+''Written'',CASE WHEN langskill=''Written'' THEN lvl ELSE NULL END )
         ) c(col_title,col_value)
     )m
     PIVOT(MAX(m.col_value) FOR m.col_title IN('+@col+')) p'

     exec(@sql)

personid    ForeignLand1         ForeignLand1Spoken   ForeignLand1Written  ForeignLand2         ForeignLand2Spoken   ForeignLand2Written  ForeignLand3         ForeignLand3Spoken   ForeignLand3Written
----------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- --------------------
101         Arabic               NULL                 Begineer             Dutch                Advanced             Medium               French               Medium               NULL
102         English              Advanced             NULL                 NULL                 NULL                 NULL                 NULL                 NULL                 NULL