2016-02-11 169 views
0

我有以下结构的表:行到列(枢轴?)

cpf   ddd phone  type origin 
11111111111 83 81021111 M  SERASA 
11111111111 83 87472222 M  SERASA 
11111111111 83 81023333 M  TRANSUNION 
11111111111 83 88724444 M  TRANSUNION 
11111111111 83 87475555 M  TRANSUNION 
22222222222 43 36271111 F  SERASA 
22222222222 44 36272222 F  SERASA 
22222222222 43 36273333 F  TRANSUNION 
22222222222 43 36284444 F  TRANSUNION 
33333333333 51 51811111 F  SERASA 
33333333333 51 56212222 F  SERASA 
33333333333 51 96213333 M  SERASA 

我需要“denormalise”这个表,所以每个CPF将只有一排,这样的事情:

使用 Pivot​​
CPF   DDD_1 PHONE_1 TYPE_1 ORIGIN_1 DDD_2 PHONE_2 TYPE_2 ORIGIN_2 DDD_3 PHONE_3 TYPE_3 ORIGIN_3 DDD_4 PHONE_4 TYPE_4 ORIGIN_4 DDD_5 PHONE_5 TYPE_5 ORIGIN_5 
11111111111 83 81021111 M  SERASA 83 87472222 M  SERASA 83 81023333 M  TRANSUNION 83 88724444 M  TRANSUNION 83  8747555 M  TRANSUNION 
22222222222 43 36271111 F  SERASA 44 36272222 F  SERASA 43 36273333 F  TRANSUNION 43 36274444 F  TRANSUNION NULL NULL  NULL NULL 
33333333333 51 51811111 F  SERASA 51 56212222 F  SERASA 51 96213333 M  SERASA  NULL NULL  NULL NULL  NULL NULL  NULL NULL 

队友的建议,但我没有找到如何使用它,因为我没有定义列的领域,还没有聚集(求和,计数等)。

我用一些数据(100行)使用表本身的联接来完成它,但由于数据量(表中有3300万行),此解决方案不起作用。

现在我卡住了,任何帮助将不胜感激。

+0

“我没有定义列的字段”这是第一步 - 使用ROWNUM创建一个查询,标识每个“cpf”组中的行号。然后pivoting将会更容易 –

+1

我更喜欢交叉表到本地数据透视表。我觉得这个语法不那么呆板,性能通常会好一点。这是一篇关于交叉表的好文章。 http://www.sqlservercentral.com/articles/T-SQL/63681/如果您需要使此动态,您可以使用动态交叉表。 http://www.sqlservercentral.com/articles/Crosstab/65048/ –

回答

1

如果你有自己的问题,问题更可能得到答案。 SO会帮助你解决代码错误和问题,但不是代码编写服务。

这就是说;它正好发生,我有一个工作的例子...

该示例使用您的示例记录,包装在一个表变量。表变量使得共享数据变得更容易,像SQL FiddleStack Data Exchange这样的服务也是如此。如果让社区更容易帮助你,你更有可能得到答案。

示例数据

/* I've used a table variable to make 
* sharing the example data easier. 
*/ 
DECLARE @Table TABLE 
    (
     cpf   VARCHAR(11), 
     ddd   INT, 
     phone  VARCHAR(10), 
     [type]  VARCHAR(1), 
     origin  VARCHAR(10) 
    ) 
; 

-- Demo values taken from OP. 
INSERT INTO @Table 
    (
     cpf, 
     ddd, 
     phone, 
     [type], 
     origin 
    ) 
VALUES 
    ('11111111111', 83, '87472222', 'M', 'SERASA'), 
    ('11111111111', 83, '81023333', 'M', 'TRANSUNION'), 
    ('11111111111', 83, '88724444', 'M', 'TRANSUNION'), 
    ('11111111111', 83, '87475555', 'M', 'TRANSUNION'), 
    ('22222222222', 43, '36271111', 'F', 'SERASA'), 
    ('22222222222', 44, '36272222', 'F', 'SERASA'), 
    ('22222222222', 43, '36273333', 'F', 'TRANSUNION'), 
    ('22222222222', 43, '36284444', 'F', 'TRANSUNION'), 
    ('33333333333', 51, '51811111', 'F', 'SERASA'), 
    ('33333333333', 51, '56212222', 'F', 'SERASA'), 
    ('33333333333', 51, '96213333', 'M', 'SERASA') 
; 

要将您的行转换成列,我测序的记录。使用ROW_NUMBER我已经为每个cpf分配了第一个记录,第二个记录为第二个记录等等。为了避免无休止地重新输入ROW_NUMBER(),我将结果转换为common table expression。 CTE是创建临时可重用数据集的好方法。最后一步是将编号为1的记录移动到第一组列中,编号为2的记录到第二组中,等等。

将行移动到列中可能值得更详细的解释。我使用CASE expressions来根据ROW_NUMBER()返回的序列号条件移动值。然后我通过cpf GROUPED的结果。用MAX包装每个个案表达式将返回所需的结果。

CASEing行转换成列

/* The records from each cdp are numbered. 
* The numbering is used to pivot the rows into 
* columns. 
*/ 
WITH Sequenced AS 
    (
     -- This CTE numbers the records for each cpf. 
     SELECT 
      ROW_NUMBER() OVER (PARTITION BY cpf ORDER BY phone) AS rn, 
      * 
     FROM 
      @Table 
    ) 
SELECT 
    cpf, 
    -- First set of columns. 
    MAX(CASE WHEN rn = 1 THEN ddd  ELSE NULL END) AS ddd_1, 
    MAX(CASE WHEN rn = 1 THEN phone  ELSE NULL END) AS phone_1, 
    MAX(CASE WHEN rn = 1 THEN [type] ELSE NULL END) AS type_1, 
    MAX(CASE WHEN rn = 1 THEN origin ELSE NULL END) AS origin_1, 

    -- Second set of columns. 
    MAX(CASE WHEN rn = 2 THEN ddd  ELSE NULL END) AS ddd_2, 
    MAX(CASE WHEN rn = 2 THEN phone  ELSE NULL END) AS phone_2, 
    MAX(CASE WHEN rn = 2 THEN [type] ELSE NULL END) AS type_2, 
    MAX(CASE WHEN rn = 2 THEN origin ELSE NULL END) AS origin_2, 

    -- Third set of columns. 
    MAX(CASE WHEN rn = 3 THEN ddd  ELSE NULL END) AS ddd_3, 
    MAX(CASE WHEN rn = 3 THEN phone  ELSE NULL END) AS phone_3, 
    MAX(CASE WHEN rn = 3 THEN [type] ELSE NULL END) AS type_3, 
    MAX(CASE WHEN rn = 3 THEN origin ELSE NULL END) AS origin_3, 

    -- Fourth set of columns 
    MAX(CASE WHEN rn = 4 THEN ddd  ELSE NULL END) AS ddd_4, 
    MAX(CASE WHEN rn = 4 THEN phone  ELSE NULL END) AS phone_4, 
    MAX(CASE WHEN rn = 4 THEN [type] ELSE NULL END) AS type_4, 
    MAX(CASE WHEN rn = 4 THEN origin ELSE NULL END) AS origin_4 
FROM 
    Sequenced 
GROUP BY 
    cpf 
; 

结果

这是很多参加。让我们分解步骤。首先,CTE添加一个分区行号:

rn cpf  ddd phone  type origin 
1 11111111111 83 81021111 M SERASA 
2 11111111111 83 87472222 M SERASA 
3 11111111111 83 81023333 M TRANSUNION 
4 11111111111 83 88724444 M TRANSUNION 
5 11111111111 83 87475555 M TRANSUNION 
1 22222222222 43 36271111 F SERASA 
2 22222222222 44 36272222 F SERASA 
3 22222222222 43 36273333 F TRANSUNION 
4 22222222222 43 36284444 F TRANSUNION 
1 33333333333 51 51811111 F SERASA 
2 33333333333 51 56212222 F SERASA 
3 33333333333 51 96213333 M SERASA 

接下来,case表达式根据行号将行移动到列中。我只包括一些列和行以方便阅读。

rn cpf   phone_1 phone_2 phone_3 
1 11111111111 81021111 NULL  NULL 
2 11111111111 NULL  87472222 NULL 
3 11111111111 NULL  NULL  87475555 

最后,分组将删除多余的行。最大功能优于空值的内容。我再次删除了行和列,以便更容易遵循。

rn cpf   phone_1 phone_2 phone_3 
1 11111111111 81021111 87472222 87475555 
2 22222222222 36271111 36272222 36273333 
... 
+0

这只是我的第一个问题,我会尽我所能让每个人都更容易帮忙(也许用我自己的代码来解决问题和查询生成示例数据)。您的解决方案运行良好,我担心它可以运行的时间,但只花了10分钟。谢谢! –

+0

表中有多少条记录?我只问,因为10分钟听起来很慢。可能能够帮助你加快速度。 –

+0

原始表中有3300万条记录,结果表中有750万条记录(我在选择之前使用了Insert Into来填充它)。由于该流程每月运行一次,所以10分钟即可,但我理解您的观点,如果您对如何加快速度提出建议,我们将非常感谢您的帮助。再次感谢! –