是否有可能创建一个多对多的关系的可编辑视图?

时间:2012-03-14 19:54:03

标签: sql sql-server-2000 sql-server-2008-r2

考虑以下表格:

产品

ID | Name | etc
1  | Pen  | wtv
2  | Pad  | wtv
3  | Ball | wtv
...| ...  | ...
thousands of products

分类

ID | Name   | etc
1  | Office | wtv
2  | Home   | wtv
3  | Park   | wtv
...| ...    | ...
hundreds of categories

productCategoryMatrix

ProductID | CategoryID
1         | 1
1         | 2
2         | 1
2         | 2
2         | 3
3         | 3
... et cetera

矩阵允许为单个产品分配多个类别(典型的多对多关系)。例如, Pen 属于两个类别, Office Home 。我希望创建此数据的可编辑视图,如下所示:

ProductsWithCategories

ProductID | ProductName | Category | Category | Category | Category | Category
1         | Pen         | 1        | 2        |          |          |
2         | Pad         | 1        | 2        | 3        |          |
3         | Ball        | 3        |          |          |          |
          |               ... Thousands of products ...             |

请注意,如果产品的分配少于5个类别,则最后一列可能保持为空,如示例所示。另请注意,业务逻辑规定永远不会有超过5个类别分配给单个产品,因此只需要五列。

是否可以使用SQL Server 2008 R2创建此类视图? 如果您的解决方案也适用于SQL Server 2000,那将是非常棒的,因为我们只在三周内升级到2008。如果没有,无论如何,我们将等待:)

2 个答案:

答案 0 :(得分:2)

任何视图都可以使用INSTEAD OF触发器进行更新。

http://msdn.microsoft.com/en-us/library/ms187956.aspx

在您的情况下,SQL Server无法自动使其可更新,但您可以将列映射到触发器中的行。

看看这些页面:

http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=120679

SQL pivoted table is read-only and cells can't be edited?

可以从中得出一个观点:

DECLARE @Products TABLE (ID INT, Name VARCHAR(50));
DECLARE @Categories AS TABLE (ID INT, Name VARCHAR(50));
DECLARE @ProductCategoryMatrix AS TABLE (ProductID INT, CategoryID INT);

INSERT INTO @Products (ID, Name) VALUES (1, 'Pen'), (2, 'Pad'), (3, 'Ball');
INSERT INTO @Categories VALUES (1, 'Office'), (2, 'Home'), (3, 'Work');
INSERT INTO @ProductCategoryMatrix VALUES (1, 1), (1, 2), (2, 1), (2, 2), (2, 3), (3, 3);

-- CREATE VIEW AS -- (change variables to real tables)
WITH CategoriesOrdered AS (
    SELECT p.ID AS ProductID
           ,'Cat' + CAST(ROW_NUMBER() OVER(PARTITION BY pc.ProductID ORDER BY pc.CategoryID) AS VARCHAR(1)) AS CategoryColumn
           ,pc.CategoryID
    FROM @Products p
    INNER JOIN @ProductCategoryMatrix pc
        ON pc.ProductID = p.ID
)
,CategoriesFlat AS (
    SELECT *
    FROM CategoriesOrdered
    PIVOT (MIN(CategoryID) FOR CategoryColumn IN ([Cat1], [Cat2], [Cat3], [Cat4], [Cat5])) AS pvt
)
,ProductsWithCategories AS (
    SELECT *
    FROM @Products p
    LEFT JOIN CategoriesFlat cf
        ON cf.ProductID = p.ID
)
SELECT *
FROM ProductsWithCategories;

对此进行触发将涉及相当多的代码,但并不是非常困难。

答案 1 :(得分:0)

这在sql 2k上完美运行,我已经测试了

select 
p.ID, 
p.Name,
c1.cid     as cat1,
c2.cid     as cat2,
c3.cid     as cat3,
c4.cid     as cat4,
c5.cid     as cat5
from 
Products p
inner join                    --  use left join if you want to have listed products with any category
   (select pcm1.ProductID, min(pcm1.CategoryID) as cid
    from productCategoryMatrix pcm1 group by ProductID) as c1 on p.ID = c1.productID

left join
   (select pcm1.productID, min(pcm2.CategoryID) as cid
    from      productCategoryMatrix pcm1
    left join productCategoryMatrix pcm2 on pcm1.productID = pcm2.productID and pcm1.CategoryID < pcm2.CategoryID
    group by pcm1.ProductID
   ) as c2 on p.ID = c2.productID

left join
   (select pcm1.productID, min(pcm3.CategoryID) as cid
    from      productCategoryMatrix pcm1
    left join productCategoryMatrix pcm2 on pcm1.productID = pcm2.productID and pcm1.CategoryID < pcm2.CategoryID
    left join productCategoryMatrix pcm3 on pcm1.productID = pcm3.productID and pcm2.CategoryID < pcm3.CategoryID
    group by pcm1.ProductID
   ) as c3 on p.ID = c3.productID

left join
   (select pcm1.productID, min(pcm4.CategoryID) as cid
    from      productCategoryMatrix pcm1
    left join productCategoryMatrix pcm2 on pcm1.productID = pcm2.productID and pcm1.CategoryID < pcm2.CategoryID
    left join productCategoryMatrix pcm3 on pcm1.productID = pcm3.productID and pcm2.CategoryID < pcm3.CategoryID
    left join productCategoryMatrix pcm4 on pcm1.productID = pcm4.productID and pcm3.CategoryID < pcm4.CategoryID
    group by pcm1.ProductID
   ) as c4 on p.ID = c4.productID

left join
   (select pcm1.productID, min(pcm5.CategoryID) as cid
    from      productCategoryMatrix pcm1
    left join productCategoryMatrix pcm2 on pcm1.productID = pcm2.productID and pcm1.CategoryID < pcm2.CategoryID
    left join productCategoryMatrix pcm3 on pcm1.productID = pcm3.productID and pcm2.CategoryID < pcm3.CategoryID
    left join productCategoryMatrix pcm4 on pcm1.productID = pcm4.productID and pcm3.CategoryID < pcm4.CategoryID
    left join productCategoryMatrix pcm5 on pcm1.productID = pcm5.productID and pcm4.CategoryID < pcm5.CategoryID
    group by pcm1.ProductID
   ) as c5 on p.ID = c5.productID