SQL Coalesce缺少值

时间:2016-09-04 20:05:56

标签: sql sql-server-2008

我有两张桌子,主人和孩子。主的主键MM是INT。子表具有两列复合键和值列:

MM (INT)
POS (INT, values 1-32)
VV (INT, values 1-9)

样本主表数据:

(1, other data)
(2, other data)
(3, other data)

示例子表数据

(1, 1,2)
(1, 2,2)
(1, 4,1)
(1,15,1)
(2, 4,5)
(2, 5,3)
(2,31,7)
(3,3,1)
(4,18,2)
{4,19,5)

对于报告,我想用这样的输出对数据进行去规范化:

(1,'22010000000000010000000000000000')
(2,'00053000000000000000000000000070')
(3,'00100000000000000000000000000000')
(4,'00000000000000000025000000000000')

我正在考虑使用这样的coalesce选择查询,但输出并不是我想要的:

(1,'22110')
(2,'537')
(3,'1')
(4,'25')

如何用零填写缺失的数据?

2 个答案:

答案 0 :(得分:3)

我认为这样做的一种方法是使用精度为32和sum()的十进制值,然后转换回零填充字符串:

select mm,
       right(replicate('0', 32) + cast(sum(val) as varchar(32)), 32)
from (select c.*,
             cast(cast(val as varchar(32)) + replicate('0', 32 - pos) as decimal(32,  0)) as val
      from child c
     ) c
group by mm;

编辑:

以上不是一般化的(例如,超过38个字符或使用字母和数字)。这是一个更通用但更长的版本:

select c.mm,
       (max(case when pos = 1 then valc else '0' end) +
        max(case when pos = 2 then valc else '0' end) +
        max(case when pos = 3 then valc else '0' end) +
        . . .
        max(case when pos = 32 then valc else '0' end) +
       )
from (select c.*, cast(val as varchar(255)) as valc
      from child c
     ) c
group by c.mm;

我应该注意,如果你想处理没有孩子的主人,那么使用left join。问题的这一方面似乎没有比在适当的位置组合值更有意思。

答案 1 :(得分:0)

尝试这样

DECLARE @master TABLE(MM INT,OtherData VARCHAR(100));
INSERT INTO @master VALUES
 (1, 'Other Data 1')
,(2, 'Other Data 2')
,(3, 'Other Data 3');

DECLARE @child TABLE(MM INT, POS INT, VV INT)
INSERT INTO @child VALUES
 (1, 1,2)
,(1, 2,2)
,(1, 4,1)
,(1,15,1)
,(2, 4,5)
,(2, 5,3)
,(2,31,7)
,(3,3,1)
,(4,18,2)
,(4,19,5);

- 获得32个数字的一​​个CTE

WITH Numbers(Nr) AS
(SELECT TOP 32 ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM sys.objects) --get 32 numbers

- 获得不同MM的另一个CTE

,MMs AS
(
    SELECT c.MM
            ,m.OtherData 
    FROM @child AS c
    LEFT JOIN @master AS m ON c.MM=m.MM
    GROUP BY c.MM,m.OtherData
)

- 在此CTE中,带有数字的CROSS JOIN将创建一个包含32行的列表,这些行在所有位置都带有相应的子数字。 COALESCE将在所有NULL的位置设置零

,Masked AS
(
    SELECT MMs.MM 
          ,MMs.OtherData
          ,Nr
          ,COALESCE(VV,0) AS Val
    FROM MMs 
    CROSS JOIN Numbers 
    LEFT JOIN @child AS c1 ON c1.MM=MMs.MM AND c1.POS=Nr
)

- 最终的SELECT使用FOR XML PATH将行中的32个数字恢复为字符串

SELECT *
      ,(
        SELECT Masked.Val AS [*]
        FROM Masked
        WHERE Masked.MM=MMs.MM
        FOR XML PATH('')
       )    
FROM MMs

结果

1   22010000000000100000000000000000
2   00053000000000000000000000000070
3   00100000000000000000000000000000
4   00000000000000000250000000000000