我遇到的情况是:
具有id列的事实表,该列不是唯一的,但永远不为null。这个事实还有很多其他维度(列),可能有一个默认值-1(逻辑上意味着为null) 例如:
id | Dimension1 | Dimension2 | Dimension3
1 Value -1 Value
1 -1 -1 Value
2 -1 Value Value
与事实表具有相同尺寸的元数据表。此表中的每一行代表事实表中的唯一ID。其余列用null或1填充,其中1表示此维度是此id的事实表中的必需维度。 例如:
id | Dimension1 | Dimension2 | Dimension3
1 1 1
2 1 1
我的目标是根据元数据表仅获取事实表中缺少必需信息的行。所以从上面的例子我只得到id = 1的行,其中Dimension1 = -1,因为元数据表说id = 1维度1和3是必需的。
有没有一种简单的方法可以做到这一点?
我做了一个非常复杂的查询,其中这两个表之间存在连接,并且所有维度之间都有一个案例检查(我有超过100个)。然后这些检查分配-1,如果维度实际上是缺失的但是是必需的,并且有一个外部查询将对所有行求和,并且仅拾取具有负和的行。 它不能100%工作,我觉得它太复杂了,无法在一个真正的大事实表上运行,所以我对这些想法持开放态度。
编辑:不允许使用动态SQL :(
答案 0 :(得分:1)
我建议使用cte和except查询...在这个解决方案中,你也必须添加案例,但是对我来说连接似乎更简单,你不需要总结任何虚拟价值......
DECLARE @t TABLE(
id int, Dimension1 int, Dimension2 int, Dimension3 int
)
DECLARE @tMeta TABLE(
id int, Dimension1 int, Dimension2 int, Dimension3 int
)
INSERT INTO @t VALUES (1, 123, -1, 345), (1, -1, -1, 246), (2, -1, 567, 987)
INSERT INTO @tMeta VALUES (1, 1, NULL, 1), (2, NULL, 1, 1)
;WITH cte AS(
SELECT id,
CASE WHEN Dimension1 = -1 THEN NULL ELSE 1 END Dimension1,
CASE WHEN Dimension2 = -1 THEN NULL ELSE 1 END Dimension2,
CASE WHEN Dimension3 = -1 THEN NULL ELSE 1 END Dimension3
FROM @t
EXCEPT
SELECT *
FROM @tMeta
EXCEPT
SELECT id, ISNULL(Dimension1,1), ISNULL(Dimension2,1), ISNULL(Dimension3,1)
FROM @tMeta
)
SELECT t.*
FROM @t t
JOIN cte c ON t.id = c.id
AND CASE WHEN t.Dimension1 = -1 THEN -1 ELSE 1 END = ISNULL(c.Dimension1, -1)
AND CASE WHEN t.Dimension2 = -1 THEN -1 ELSE 1 END = ISNULL(c.Dimension2, -1)
AND CASE WHEN t.Dimension3 = -1 THEN -1 ELSE 1 END = ISNULL(c.Dimension3, -1)
答案 1 :(得分:0)
你可以使用UNPIVOT来简化查询,你也不会在事实表中使用ROWId,因此第一个让ROW_NUMBER()作为事实表中的RowId的CTE。然后我们制作不透明的表(事实和模板表)并加入它们:
WITH TFBase AS
(
SELECT TF.*, ROW_NUMBER() OVER (ORDER BY ID) as TableRowID FROM TF
),
TFU AS
(
select id,TableRowID,dim,val
from TFBase
unpivot
(
val for dim in (Dimension1, Dimension2, Dimension3)
) u
WHERE U.Val <>-1
)
,
TFT AS
(
select id,dim,val
from TTemplate
unpivot
(
val for dim in (Dimension1, Dimension2, Dimension3)
) u
WHERE Val is NOT NULL
)
SELECT * FROM TFBase WHERE
TableRowID IN
(
SELECT TableRowID FROM TFU
LEFT JOIN TFT ON
(TFU.id=TFT.id) AND (TFU.dim = TFT.dim)
GROUP BY TableRowID, TFU.ID
HAVING COUNT(TFT.Val) <> (SELECT COUNT(*) FROM TFT WHERE ID = TFU.ID)
)