不同表的SQL Server外键

时间:2013-05-30 15:00:11

标签: sql sql-server database-design

我有一个SQL Server 2012 Express数据库,其中包含以下情况。 我有一个Sales,一个Purchase和一个Movement表。 SalesPurchase都汇总在Movement表中。

但我想控制数据的来源。 基本上是:

MOVEMENT_ID     TABLE_ID     RECORD_ID     PROD     QTY
1               PURCHASE     1             PENCIL   10
2               PURCHASE     2             ERASER   5
3               SALES        1             PENCIL   1
4               PURCHASE     3             MARKER   10

不要担心规范化部分,我只是想知道我是否可以在Record_ID列上有一个外键,该列链接到Table_ID列中指定的表的记录。 所以......

  • MovementID=1上,我想要Purchase table
  • 的第一条记录
  • MovementID=3上,我想要Sales table
  • 的第一条记录

这一切都可能吗?如果是,怎么样?

3 个答案:

答案 0 :(得分:1)

  

这一切都可能吗?

不是直接的,我会热烈推荐单独的字段与单独的FK(正如其他人已经建议的那样)。

然而,因为你使用的是MS SQL Server,你可以像这样间接地做到这一点:

  1. 创建一个持久的 1 计算列 SALE_ID,即:
      当TABLE_ID =' SALES' 时,
    • 等于RECORD_ID
    • ,否则为NULL。
  2. 创建一个持久计算列PURCHASE_ID,它是:
      当TABLE_ID ='购买' 时,
    • 等于RECORD_ID
    • ,否则为NULL。
  3. 从SALE_ID到Sales表创建一个FK,从PURCHASE_ID到Purchase表创建一个单独的FK。
  4. 例如:

    ALTER TABLE Movement
        ADD SALE_ID AS IIF(TABLE_ID = 'SALES', RECORD_ID, NULL) PERSISTED
        REFERENCES Sales (SALE_ID);
    
    ALTER TABLE Movement
        ADD PURCHASE_ID AS IIF(TABLE_ID = 'PURCHASE', RECORD_ID, NULL) PERSISTED
        REFERENCES Purchase (PURCHASE_ID);
    

    [SQL Fiddle]


    1 SQL Server禁止在非持久计算列上创建FOREIGN KEY。

答案 1 :(得分:0)

根据你为此做了什么,这样的非规范化表可能不会太糟糕(即它只是用于查询/分析)。但是,它可能变得难以维护(例如,当这些表中的ID具有不同的数据类型等时会发生什么)。您可能会做的一些查询示例

;WITH SalesMovement AS
(
    SELECT * FROM Movement
    WHERE TableName = 'Sales'
)
SELECT PROD, SUM(QTY) FROM SalesMovement
GROUP BY PROD

;WITH PurchaseMovement AS
(
    SELECT * FROM Movement
    WHERE TableName = 'Purchase'
)
SELECT * FROM Purchase p
INNER JOIN PurchaseMovement pm ON pm.Record_Id = p.Id

;WITH PurchaseMovement AS
(
    SELECT * FROM Movement
    WHERE TableName = 'Purchase'
)
, SalesMovement AS
(
    SELECT * FROM Movement
    WHERE TableName = 'Sales'
)
SELECT * FROM Purchase p, 
INNER JOIN Sales s ON s.SaleDate = p.PurchaseDate
INNER JOIN PurchaseMovement pm ON pm.Record_Id = p.Id
INNER JOIN SalesMovement sm ON sm.Record_Id = s.Id

每当你想加入原始数据时,你都需要过滤,投射以及你可能会成为真正的皮塔的东西

要考虑的另一件事是SUM(Qty) = SUM(ProductsSold) + SUM(ProductsSales)这样的东西是否有意义,你必须小心这种“误用”表格中的数据。

答案 2 :(得分:0)

听起来运动真的是购买或销售的概括。如果是,请考虑使用

这将消除在一列中混合不同类型的FK的问题。移动表中的PK将根据具体情况在购买或销售表中引用PK。更少的列,也更少混乱。