我有两张桌子,主人和孩子。主的主键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')
如何用零填写缺失的数据?
答案 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