2009-11-10 75 views
1

我有一个复杂的(对我来说任何方式)查询困难。帮助一个复杂的自查询跨多个colums

我的表查询有3个colums,客户端ID(INT NOT NULL),产品ID(INT NOT NULL)和ExpiryDate(SMALLDATETIME可为空)

给出两个客户端ID的硕士及合并我需要执行以下业务逻辑返回单个数据集:

选择具有更大的 到期日ClientID的一种产品,其中到期 日期双方的ClientID不是空

与选择的ClientID ULL到期 日期产品,其中一个过期而 空,另一个不为空

选择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 

任何和所有帮助非常感谢

编辑:虽然它听起来像它,这不是作业,但一个真实的生活问题,我希望找到一个真正的生活解决方案,我可以自己做这件事,但我所有的解决方案都是通往临时表的路径。我应该指出生产环境是SQLServer 7!

+0

我真的很难相信3个查询不是功课。 – 2009-11-10 06:22:48

+0

也许我还不清楚。我在一个查询之后,显然是子查询的结果。不,这不是家庭作业,但真的不在乎它是否被标记为 – 2009-11-10 06:37:17

回答

1

在这里我已经将条件移动到子查询。子查询连接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 
+0

许多感谢!比临时表路线更简洁,我正在往下走! – 2009-11-10 07:06:34

0

的问题是不明确的,但我把它解释,或许是这样的:

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