Помощь в сложном запросе самореференции через несколько столбцов - PullRequest
1 голос
/ 10 ноября 2009

У меня проблемы со сложным (для меня любым способом) запросом.

Таблица, которую я запрашиваю, имеет 3 столбца, ClientID (int, не Null), ProductID (int, не Null) и ExpiryDate (smalldatetime, обнуляемый)

Учитывая два идентификатора клиента: Master и Consolidated, мне нужно выполнить следующую бизнес-логику для возврата одного набора данных:

Выберите ClientID с большим срок годности продукта, срок годности которого истек даты обоих идентификаторов клиентов не равны

Выберите 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

Любая и вся помощь очень ценится

РЕДАКТИРОВАТЬ: Хотя это звучит так, это не домашняя работа, а реальная проблема жизни, я надеюсь найти решение реальной жизни, я мог бы сделать это сам, но все мои решения ведут вниз путь к временным таблицам. Следует отметить, что производственной средой является SQLServer 7!

Ответы [ 2 ]

1 голос
/ 10 ноября 2009

Здесь я перенес условия в подзапрос. Подзапрос объединяет строки для 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 голосов
/ 10 ноября 2009

Вопрос не ясен, но, насколько я понимаю, возможно что-то вроде:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...