【问题标题】:Transposing and identifying the cell with a flag用标志转置和识别单元格
【发布时间】:2016-10-26 14:31:51
【问题描述】:

我有一个三列的表。值列始终为NULL。我知道如何将行转换为列,但我也想用“X”标识单元格。

表格

EditorTypeSymbolicName ClaimFieldSymbolicName Value
01                     AA                     NULL
01                     BB                     NULL
01                     CC                     NULL
02                     BB                     NULL
02                     CC                     NULL
03                     AA                     NULL

这是我的代码

DECLARE @cols NVARCHAR(MAX), @sql NVARCHAR(MAX)

SET @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(ClaimFieldSymbolicName)
            FROM #TempEditElements
            ORDER BY 1
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)'),1,1,'')

SET @sql = 'SELECT EditorTypeSymbolicName, ' + @cols + '
              FROM
            (
              select EditorTypeSymbolicName, ClaimFieldSymbolicName, Value 
              from #TempEditElements
            ) s
            PIVOT
            (
              MAX(Value) FOR ClaimFieldSymbolicName IN (' + @cols + ')
            ) p
            order by EditorTypeSymbolicName'

EXECUTE(@sql)

我的代码转置了它,但我不知道如何用“X”标记它们。我希望输出如下:

EditorTypeSymbolicName  AA   BB   CC
01                      X    X    X
02                      NULL X    X
03                      X    NULL NULL

当前输出如下所示

EditorTypeSymbolicName  AA   BB   CC
01                      NULL NULL NULL
02                      NULL NULL NULL
03                      NULL NULL NULL

【问题讨论】:

  • 你说的identify是什么意思?是否要将结果限制为 Value 列中包含“X”的行?
  • 当前输出是什么样的?你能把它添加到你的问题中吗?
  • @TT - 添加当前输出。
  • @Gerardo Lima - 当将 ClaimFieldSymbolicName 转置为列时,我想通过 X 识别 EditorTypeSymbolicName 具有 ClaimFieldSymbolicName 的位置

标签: sql-server sql-server-2008 tsql pivot


【解决方案1】:

这将是一种方法。在动态查询中,

  • 为EditorTypeSymbolicName X ClaimFieldSymbolicName(CROSS JOIN 部分)创建了一个“矩阵”
  • 然后将其链接到原始表以查找每个组合是否存在一行(LEFT JOIN 部分)
  • 如果存在一行,Value 将替换为您需要的 X(Value=CASE ... 部分)

CREATE TABLE #TempEditElements(EditorTypeSymbolicName VARCHAR(128),ClaimFieldSymbolicName VARCHAR(128),Value VARCHAR(128));
INSERT INTO #TempEditElements(EditorTypeSymbolicName,ClaimFieldSymbolicName,Value)
VALUES ('01','AA',NULL),('01','BB',NULL),('01','CC',NULL),('02','BB',NULL),('02','CC',NULL),('03','AA',NULL);

DECLARE @cols NVARCHAR(MAX), @sql NVARCHAR(MAX);

SET @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(ClaimFieldSymbolicName)
            FROM #TempEditElements
            ORDER BY 1
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)'),1,1,'')

SET @sql = 'SELECT EditorTypeSymbolicName, ' + @cols + '
              FROM
            (
                SELECT 
                    ets.EditorTypeSymbolicName,
                    cfs.ClaimFieldSymbolicName,
                    Value=CASE WHEN tee.EditorTypeSymbolicName IS NULL AND tee.ClaimFieldSymbolicName IS NULL THEN NULL ELSE ''X'' END
                FROM
                    (SELECT DISTINCT EditorTypeSymbolicName FROM #TempEditElements) AS ets
                    CROSS JOIN (SELECT DISTINCT ClaimFieldSymbolicName FROM #TempEditElements) AS cfs
                    LEFT JOIN #TempEditElements AS tee ON 
                        tee.EditorTypeSymbolicName=ets.EditorTypeSymbolicName AND 
                        tee.ClaimFieldSymbolicName=cfs.ClaimFieldSymbolicName
            ) s
            PIVOT
            (
              MAX(Value) FOR ClaimFieldSymbolicName IN (' + @cols + ')
            ) p
            order by EditorTypeSymbolicName'

EXECUTE (@sql);

DROP TABLE #TempEditElements;

结果是:

╔════════════════════════╦══════╦══════╦══════╗
║ EditorTypeSymbolicName ║  AA  ║  BB  ║  CC  ║
╠════════════════════════╬══════╬══════╬══════╣
║                     01 ║ X    ║ X    ║ X    ║
║                     02 ║ NULL ║ X    ║ X    ║
║                     03 ║ X    ║ NULL ║ NULL ║
╚════════════════════════╩══════╩══════╩══════╝

【讨论】:

  • 感谢您的解答:
  • (1) value 应该没有逻辑,它只是 'X' (2 ) PIVOT 的工作方式,没有理由生成 EditorTypeSymbolicName 和 ClaimFieldSymbolicName 的所有组合。一旦您在 EditorTypeSymbolicName 中有一个值,就会在数据透视表中创建一行。对于基于 ClaimFieldSymbolicName 创建的列,您已经在上一部分中注意了。如果原始表中至少有一行具有 EditorTypeSymbolicName 和 ClaimFieldSymbolicName 值,则数据透视表中的任何正方形都将包含“X”,否则为 NULL。
  • @DuduMarkovitz 你说得对。对于这样的问题,我并没有真正将解决方案变成最好的,我只是想出了一些可行的方法。
  • @TT.P.s.您是如何生成结果表的?
  • @DuduMarkovitz 执行脚本,然后在 SSMS 中右键单击结果表的左上角标题并选择“带标题复制”。转到senseful.github.io/web-tools/text-table 并将表格粘贴到输入字段中。在样式中选择“Unicode Art”,点击“Generate Table”。在输出中全选。然后粘贴在答案字段中并格式化为代码块。查看我的个人资料以获取更多有趣的链接。
【解决方案2】:

静态解决方案

select      *

from        (select 'X' as x,EditorTypeSymbolicName,ClaimFieldSymbolicName from t) t 
                pivot (max(x) for ClaimFieldSymbolicName in ([AA],[BB],[CC]))   t

order by    EditorTypeSymbolicName
;

动态解决方案

declare @columns    nvarchar(max)   = ''
       ,@stmt       nvarchar(max)
;

----------

select      @columns += case @columns when '' then '' else ',' end + QUOTENAME (ClaimFieldSymbolicName,'[')

from        t

group by    ClaimFieldSymbolicName

order by    ClaimFieldSymbolicName
;

----------

set @stmt =

    '
    select      *

    from        (select ''X'' as x,EditorTypeSymbolicName,ClaimFieldSymbolicName from t) t 
                    pivot (max(x) for ClaimFieldSymbolicName in ('+ @columns + '))   t

    order by    EditorTypeSymbolicName
    '
;

----------

exec (@stmt)

半静态解决方案

select      (select top 0 EditorTypeSymbolicName from t) as EditorTypeSymbolicName,t.*

from        (select distinct ClaimFieldSymbolicName,dense_rank () over (order by ClaimFieldSymbolicName) as dr from t) t 
                pivot (max(ClaimFieldSymbolicName) for dr in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10])) t


union all

select      *

from        (select 'X' as x,EditorTypeSymbolicName,dense_rank () over (order by ClaimFieldSymbolicName) as dr from t) t 
                pivot (max(x) for dr in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10])) t

order by    1
;

╔════════════════════════╦══════╦══════╦══════╦══════╦══════╦══════╦══════╦══════╦══════╦══════╗
║ EditorTypeSymbolicName ║  1   ║  2   ║  3   ║  4   ║  5   ║  6   ║  7   ║  8   ║  9   ║  10  ║
╠════════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣
║ NULL                   ║ AA   ║ BB   ║ CC   ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║
║ 01                     ║ X    ║ X    ║ X    ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║
║ 02                     ║ NULL ║ X    ║ X    ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║
║ 03                     ║ X    ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║
╚════════════════════════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╝

【讨论】:

  • 我需要它是动态的,因为转置的列数很多
  • @user176047,这意味着您只需连接列标识符,例如 AA,BB,CC 并将其推送到此查询中。我相信你会做到的
  • 是的,我尝试在“t.ClaimFieldSymbolicName in ('at'cols))”中使用 'at'cols,但出现语法错误。我声明了 'at'cols 并用列名填充它,就像我在 OP 中的上述查询一样。
  • @user176047,请查看动态解决方案(已编辑答案)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-17
  • 1970-01-01
  • 1970-01-01
  • 2013-07-15
  • 2022-07-21
  • 1970-01-01
相关资源
最近更新 更多