T-SQL Triple Self Join

时间:2009-11-20 16:04:46

标签: tsql

嘿伙计们,我对下表有疑问:

CREATE TABLE [dbo].[CA](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Type] [char](1),
[Percent] [numeric](19, 5) NULL,
[Crop] [int] NULL,
[Currency] [int] NULL,
[Ammount] [decimal](19, 5) 
[ProductionSite] [int] NOT NULL
)

此表描述了ProductionSite如何向其供应商付款。它可能与作物,金额或此处未列出的其他金额的百分比有关。

'type'列是一个鉴别器,用于指示付费类型。 问题是,您可以同时支付三个选项,两个或一个。因此,对于给定的ProductionSite,表中最多可以有三行(此设计无法更改)

我需要创建一个视图(不允许SP /触发器),每个ProductionSite只显示一行。

我不确定我是否遗漏了一些东西,但是我遇到了很多麻烦:(

几乎忘了,这还有一个额外的问题。视图的列顺序必须始终相同。我这样说,因为查询计划并不总是确定性的(如果我是正确的)所以三重自我关联可能会给出不同的结果(按列/行顺序,而不是数据)。为了清楚起见,

SELECT * FROM A LEFT JOIN A AS B LEFT JOIN A AS C

可能会返回以下内容的一部分:

columns(a) + columns(b) + columns(c)
columns(b) + columns(a) + columns(c)
etc..

任何建议/答案都将非常感激:)

3 个答案:

答案 0 :(得分:1)

首先获取生产站点的明确列表,然后左键加入表格中的类型。

像这样的东西

DECLARE @CA TABLE (
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Type] [char](1),
    [Percent] [numeric](19, 5) NULL,
    [Crop] [int] NULL,
    [Currency] [int] NULL,
    [Ammount] [decimal](19, 5),
    [ProductionSite] [int] NOT NULL
    )


SELECT  *
FROm    (
            SELECT  DISTINCT 
                    [ProductionSite]
            FROM    @CA
        ) DistinctSites LEFT JOIN
        @CA cType1 ON DistinctSites.ProductionSite = cType1.ProductionSite AND cType1.Type = 'Type1' LEFT JOIN
        @CA cType2 ON DistinctSites.ProductionSite = cType2.ProductionSite AND cType1.Type = 'Type2' LEFT JOIN
        @CA cType3 ON DistinctSites.ProductionSite = cType3.ProductionSite AND cType1.Type = 'Type3'

答案 1 :(得分:1)

CREATE VIEW ThreePossiblePaymentDetailsAtOnce AS
SELECT COALESCE(T1.id, T2.id, T3.Id) AS SiteID,
       CASE 
         WHEN T1.id IS NOT NULL THEN T1.ProductionSite
         WHEN T2.id IS NOT NULL THEN T2.ProductionSite
         ELSE T3.ProductionSite
       END AS ProdSite,
       T1.Type, T1.Percent, T1.Crop,
       T2.Type, T2.Percent, T2.Currency,
       T3.Type, T3.Percent, T3,Ammount
FROM CA AS T1
FULL JOIN CA AS T2 ON T2.id = T1.id AND T2.Type = type_for_Currenty
FULL JOIN CA AS T3 ON T2.id = T1.id AND T2.Type = type_for_Ammount
WHERE T1.Type = type_for_crops
--AND here for additional conditions if desired
ORDER BY   -- or of course any other desired order, if any.
       CASE 
         WHEN T1.id IS NOT NULL THEN T1.ProductionSite
         WHEN T2.id IS NOT NULL THEN T2.ProductionSite
         ELSE T3.ProductionSite
       END

<强>解释
FULL JOIN提供了一种方便的方法,可以在同一结果行中引入所有行(对于给定的Id +付款类型)。难点是确保显示Id(我也假设了ProductionSite名称),只需一次,无论它来自何处。
一种方法(参见Astander的解决方案),首先获得一个独特的Ids + ProductionSite值列表,并使用它来驱动查询。
此解决方案是另一种选择,使用COALESCE,它基本上找到第一个非空Id。我们可能会很好地使用COALESCE来生成ProductionSite AS,我认为我会在ID的nullness上使用CASE,可能在语义上更正确。

答案 2 :(得分:0)

试试这个

   Select c.ProductionSite, 
       Coalesce(c.type, m.type, p.type) type,
       c.Crop, m.Currency, p.Percent,
       Coalesce(c.type, m.type, p.type) type,
       Coalesce(c.Amount, m.Amount, p.Amount) Amount  
   From CA c -- for crops
     Full Join CA m -- for money
        On m.ProductionSite = c.ProductionSite
           And c.type = 'c'
           And m.type = 'm'
     Full Join CA p -- for percentage
        On p.ProductionSite = c.ProductionSite
           And c.type = 'c'
           And p.type = 'p'