views:

2293

answers:

2

Hello Everyone,

I have an interesting SQL problem that I need help with.

Here is the sample dataset:

Warehouse  DateStamp   TimeStamp  ItemNumber  ID
    A       8/1/2009    10001         abc      1
    B       8/1/2009    10002         abc      1 
    A       8/3/2009    12144         qrs      5
    C       8/3/2009    12143         qrs      5
    D       8/5/2009    6754          xyz      6
    B       8/5/2009    6755          xyz      6

This dataset represents inventory transfers between two warehouses. There are two records that represent each transfer, and these two transfer records always have the same ItemNumber, DateStamp, and ID. The TimeStamp values for the two transfer records always have a difference of 1, where the smaller TimeStamp represents the source warehouse record and the larger TimeStamp represents the destination warehouse record.

Using the sample dataset above, here is the query result set that I need:

Warehouse_Source  Warehouse_Destination  ItemNumber  DateStamp
    A                B                      abc       8/1/2009
    C                A                      qrs       8/3/2009
    D                B                      xyz       8/5/2009

I can write code to produce the desired result set, but I was wondering if this record combination was possible through SQL. I am using SQL Server 2005 as my underlying database. I also need to add a WHERE clause to the SQL, so that for example, I could search on Warehouse_Source = A. And no, I can't change the data model ;).

Any advice is greatly appreciated!

Regards, Mark

+5  A: 
SELECT source.Warehouse as Warehouse_Source 
, dest.Warehouse as Warehouse_Destination
, source.ItemNumber
, source.DateStamp
FROM table source
JOIN table dest ON source.ID = dest.ID 
  AND source.ItemNumber = dest.ItemNumber
  AND source.DateStamp = dest.DateStamp
  AND source.TimeStamp = dest.TimeStamp + 1
Remus Rusanu
Perfect! Thank you...
Mark Lansdown
A: 

Mark,

Here is how you can do this with row_number and PIVOT. With a clustered index or primary key on the columns as I suggest, it will use a straight-line query plan with no Sort operation, thus be particularly efficient.

create table T(
  Warehouse char,
  DateStamp datetime,
  TimeStamp int,
  ItemNumber varchar(10),
  ID int,
  primary key(ItemNumber,DateStamp,ID,TimeStamp)
);
insert into T values ('A','20090801','10001','abc','1');
insert into T values ('B','20090801','10002','abc','1'); 
insert into T values ('A','20090803','12144','qrs','5');
insert into T values ('C','20090803','12143','qrs','5');
insert into T values ('D','20090805','6754','xyz','6');
insert into T values ('B','20090805','6755','xyz','6');

with Tpaired(Warehouse,DateStamp,TimeStamp,ItemNumber,ID,rk) as (
  select
    Warehouse,DateStamp,TimeStamp,ItemNumber,ID,
    row_number() over (
      partition by ItemNumber,DateStamp,ID
      order by TimeStamp
    )
  from T
)
  select
    max([1]) as Warehouse_Source,
    max([2]) as Warehouse_Destination,
    ItemNumber,
    DateStamp
  from Tpaired
  pivot (
    max(Warehouse) for rk in ([1],[2])
  ) as P
  group by ItemNumber, DateStamp, ID;
go

drop table T;
Steve Kass