使用元数据表

时间:2016-11-30 13:59:23

标签: sql sql-server

我遇到的情况是:

  1. 具有id列的事实表,该列不是唯一的,但永远不为null。这个事实还有很多其他维度(列),可能有一个默认值-1(逻辑上意味着为null) 例如:

    id   |  Dimension1  | Dimension2  | Dimension3
    1           Value         -1           Value
    1           -1            -1           Value
    2           -1           Value         Value
    
  2. 与事实表具有相同尺寸的元数据表。此表中的每一行代表事实表中的唯一ID。其余列用null或1填充,其中1表示此维度是此id的事实表中的必需维度。 例如:

    id   |  Dimension1  | Dimension2  | Dimension3
    1           1                           1
    2                         1             1
    
  3. 我的目标是根据元数据表仅获取事实表中缺少必需信息的行。所以从上面的例子我只得到id = 1的行,其中Dimension1 = -1,因为元数据表说id = 1维度1和3是必需的。

    有没有一种简单的方法可以做到这一点?

    我做了一个非常复杂的查询,其中这两个表之间存在连接,并且所有维度之间都有一个案例检查(我有超过100个)。然后这些检查分配-1,如果维度实际上是缺失的但是是必需的,并且有一个外部查询将对所有行求和,并且仅拾取具有负和的行。 它不能100%工作,我觉得它太复杂了,无法在一个真正的大事实表上运行,所以我对这些想法持开放态度。

    编辑:不允许使用动态SQL :(

2 个答案:

答案 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) 
 )