代码之家  ›  专栏  ›  技术社区  ›  MW_dev

帮助跨多个列进行复杂的自引用查询

  •  1
  • MW_dev  · 技术社区  · 15 年前

    我对一个复杂的(无论如何)问题有困难。

    我查询的表有3列,clientID(int不为空)、productID(int不为空)和expiryDate(smalldatetime可以为空)

    给定两个客户机ID的主ID和合并ID,我需要执行以下业务逻辑以返回单个数据集:

    选择具有较大值的clientID 产品到期日 两个客户端ID的日期不为空

    选择有效期为空的clientid 产品到期日为 空,另一个不空

    选择产品的MasterID 两个到期日均为空或 两个有效期相同。

    我试过以下方法,但是卡住了…

    Create Table #ProductSub (ClientID int NOT NULL, 
                              ProductID int NOT NULL, 
                              ExpiryDate smalldatetime)  
    
    /* In real life there is a Clustered Primary Key On ClientID and ProductID
       Load Up Some Test Data */  
    
      Insert into #ProductSub  Values (1, 100, null)
      Insert into #ProductSub  Values (2, 100, null)
      Insert into #ProductSub  Values (1, 101, null)
      Insert into #ProductSub  Values (2, 102, null)
      Insert into #ProductSub  Values (1, 200, null)
      Insert into #ProductSub  Values (2, 200, '2009-01-01')
      Insert into #ProductSub  Values (1, 300, '2009-01-01')
      Insert into #ProductSub  Values (2, 300, null)
      Insert into #ProductSub  Values (1, 400, '2009-01-01')
      Insert into #ProductSub  Values (2, 400, '2008-01-01')
      Insert into #ProductSub  Values (1, 500, '2008-01-01')
      Insert into #ProductSub  Values (2, 500, '2009-01-01')
      Insert into #ProductSub  Values (1, 600, '2009-01-01')
      Insert into #ProductSub  Values (2, 600, '2009-01-01')  
    
     --Select * from #ProductSub  
    
      Declare @MasterClient int,
              @ConsolClient int
    
      Select @MasterClient = 1, @ConsolClient = 2  
    
    
    Select * from #ProductSub t1
      /* Use Master Client ID When Expiry Date is Null) */
      Where (ClientID = @MasterClient and ExpiryDate is null)
      /* Use Consol ClientID if Expiry Date is null nut Expiry Date for Master Client ID is not */
      OR    (ClientID = @ConsolClient and ExpiryDate is null and ProductID not in (
                Select ProductID from #ProductSub t2
                Where (ClientID = @MasterClient and ExpiryDate is null))
            ) 
      OR   -- OH NO my head exploded
    /*  OR EXISTS (Select 1
                 from #ProductSub t3
                )*/
    
    Drop Table #ProductSub   
    
    /**********  Expected  Output  ************************
    ClientID     ProductID     ExpiryDate
    1            100           NULL
    1            101           NULL
    2            102           NULL
    1            200           NULL
    2            300           NULL
    1            400           2009-01-01 00:00:00
    2            500           2009-01-01 00:00:00
    1            600           2009-01-01 00:00:00
    

    任何帮助都非常感谢

    编辑: 虽然这听起来像是,但这不是家庭作业,而是我希望找到一个现实生活的解决方案,我可以自己做,但我所有的解决方案都是通往临时表的道路。我应该指出生产环境是SQLServer7!

    2 回复  |  直到 15 年前
        1
  •  1
  •   Andomar    15 年前

    在这里,我将条件移动到了子查询。子查询联接consol和master的行,这样您就可以从这两行访问列。条件仍然有点复杂,因为任何一行都可能丢失。

    select ps.*
    from @ProductSub ps
    inner join (
        select     
          CASE 
            WHEN c.ClientID is null THEN m.ClientID
            WHEN m.ClientID is null THEN c.ClientID
            WHEN m.ExpiryDate is not null and c.ExpiryDate is not null THEN
              CASE 
                WHEN c.ExpiryDate > m.ExpiryDate THEN c.ClientID
                ELSE m.ClientID
              END
            WHEN m.ExpiryDate is null THEN m.ClientID
            WHEN c.ExpiryDate is null THEN c.ClientID
            ELSE m.ClientID
          END as ClientId,
          COALESCE(m.ProductId, c.ProductId) as ProductId
        from       @ProductSub m
        full outer join  @ProductSub c
        on         m.ProductID = c.ProductID
        and        m.ClientID <> c.ClientID
        where      IsNull(m.clientid,@MasterClient) = @MasterClient
        and        IsNull(c.clientid,@ConsolClient) = @ConsolClient
    ) filter
    on filter.clientid = ps.clientid
    and filter.productid = ps.productid
    order by ps.ProductId
    
        2
  •  0
  •   Marc Gravell    15 年前

    这个问题不太清楚,但正如我所解释的,可能是:

    DECLARE @MasterExpiry smalldatetime, @ConsolExpiry smalldatetime
    SELECT @MasterExpiry = ExpiryDate FROM #ProductSub WHERE ClientID = @MasterClient
    SELECT @ConsolExpiry = ExpiryDate FROM #ProductSub WHERE ClientID = @ConsolClient
    
    SELECT CASE
        WHEN @MasterExpiry IS NULL AND @ConsolExpiry IS NULL THEN @MasterClient
        WHEN @MasterExpiry IS NULL THEN @MasterClient
        WHEN @ConsolExpiry IS NULL THEN @ConsolClient
        WHEN @MasterExpiry >= @ConsolExpiry THEN @MasterClient
        ELSE @ConsolClient END AS [Client]
    

    如果需要行数据,请将其选入变量,然后分别执行 SELECT ?

    DECLARE @FinalClient int
    SELECT @FinalClient = CASE
        WHEN @MasterExpiry IS NULL AND @ConsolExpiry IS NULL THEN @MasterClient
        WHEN @MasterExpiry IS NULL THEN @MasterClient
        WHEN @ConsolExpiry IS NULL THEN @ConsolClient
        WHEN @MasterExpiry >= @ConsolExpiry THEN @MasterClient
        ELSE @ConsolClient END
    
    SELECT * FROM #ProductSub WHERE ClientID = @FinalClient
    
    推荐文章