2016-11-24 95 views
0

我的下面的代碼工作正常。它所做的是它將更新每個產品編號,當它移動到新位置有沒有更好的方法來檢索這些數據?

select 
a.loc1 As [Location 1], 
b.loc2 as [Location 2], 
c.loc3 as [Location 3], 
d.loc4 as [Location 4] 

FROM (select distinct a.ProductNR as Loc1 
from LocationsTest a 
where a.Date= (select max(Date) from LocationsTest where a.ProductNR = ProductNR) 
AND a.Location = 1) as a 

FULL OUTER JOIN 

(select distinct a.ProductNR as Loc2 
from LocationsTest a 
where a.Date= (select max(Date) from LocationsTest where a.ProductNR = ProductNR) 
AND a.Location = 2) as b 
on a.Loc1 = b.Loc2 

FULL OUTER JOIN 

(select distinct a.ProductNR as Loc3 
from LocationsTest a 
where a.Date= (select max(Date) from LocationsTest where a.ProductNR = ProductNR) 
AND a.Location = 3) as c 
ON ISNULL(A.Loc1, b.Loc2) = c.Loc3 

FULL OUTER JOIN 

(select distinct a.ProductNR as Loc4 
from LocationsTest a 
where a.Date= (select max(Date) from LocationsTest where a.ProductNR = ProductNR) 
AND a.Location = 4) as d 
ON ISNULL(b.Loc2, c.Loc3) = d.Loc4 

一個例子來說明它如何工作,是因爲你可以看到在他們不同的產品編號下面的4個地點。

---------------------------------------------------------- 
| Location 1 | Location 2 | Location 3 | Location 4 
---------------------------------------------------------- 
| 1234   |    |    |   |   
| 4567   |    |    |   | 
| 8978   |    |    |   | 
| 2578   |    |    |   | 
---------------------------------------------------------- 

當一個產品以後獲取的掃描到一個新的位置,它仍然會留在我的歷史數據,因爲它是在位置1,但我上面的查詢顯示了它這樣的:

---------------------------------------------------------- 
| Location 1 | Location 2 | Location 3 | Location 4 
---------------------------------------------------------- 
|    | 1234   |    |   |   
| 4567   |    |    |   | 
| 8978   |    |    |   | 
| 2578   |    |    |   | 
---------------------------------------------------------- 

它的檢索基於上次更新日期的數據。 問題是我上面的代碼看起來很長,特別是當我打算在將來添加更多位置時。 那麼有更好的方法來做到這一點?

編輯 - 示例數據:

CREATE TABLE LocationsTest 
(
ProductNR varchar (14), 
Location int, 
Date Datetime, 

); 

Insert Into LocationsTest (ProductNR, Location, Date) 
Values('1234', 1, '2016-11-17 12:30:50.010'), 
     ('4567', 1, '2016-11-17 12:35:50.010'), 
     ('8978', 1, '2016-11-17 12:37:50.010'), 
     ('2578', 1, '2016-11-17 12:50:50.010'); 
+0

請提供源表格和一些數據來填充它們。 – iamdave

+0

這不是真正的表格,它是與我的數據庫中幾乎相同的表格的一個例子。 你知道我可以上傳一些數據的網站嗎?像小提琴? – MishMish

+0

@MishMish您是否跟蹤產品從一個位置移動到另一個位置?如果有一張表保持一個產品所遍歷的所有位置,這將是一個簡單的查詢。基本上,如果你需要歷史數據,你需要跟蹤它。 –

回答

0

我得到你想從你的SQL代碼,這通常是一個禁忌之內找到一個解決方案格式化的印象。數據看起來應該留給你的表示層。

除此之外,下面的代碼包含兩個例子;首先是你可能應該將您的數據返回到您的應用程序層,第二個是您請求的格式。隨着新的位置但是包括在內,你需要不斷更新的PIVOT聲明,包括他們:

CREATE TABLE LocationsTest 
(
ProductNR varchar (14), 
Location int, 
Date Datetime 

); 

Insert Into LocationsTest (ProductNR, Location, Date) 
Values('1234', 1, '2016-11-17 12:30:50.010'), 
     ('4567', 1, '2016-11-17 12:35:50.010'), 
     ('8978', 1, '2016-11-17 12:37:50.010'), 
     ('2578', 1, '2016-11-17 12:50:50.010'), 
     ('1234', 2, '2016-11-18 12:30:50.010'); -- I have added this row to simulate a Location move. 

-- This just drops out the relevant data for use in application level formatting: 
with mr 
as 
(
    select ProductNR 
      ,max(Date) as MostRecent 
    from LocationsTest 
    group by ProductNR 
) 
select l.ProductNr 
     ,l.Location 
from LocationsTest l 
    inner join mr 
     on l.ProductNR = mr.ProductNR 
      and l.Date = mr.MostRecent; 


-- This actually PIVOTs the data for you, but will need updating for every new location: 
with mr 
as 
(
    select ProductNR 
      ,max(Date) as MostRecent 
    from LocationsTest 
    group by ProductNR 
) 
select [1] as Location1 
     ,[2] as Location2 
     ,[3] as Location3 
     ,[4] as Location4 
from(
    select l.ProductNr 
      ,l.ProductNr as ProductNr2 -- This ensures all rows are returned in the PIVOT 
      ,l.Location 
    from LocationsTest l 
     inner join mr 
      on l.ProductNR = mr.ProductNR 
       and l.Date = mr.MostRecent 
) d 
pivot 
(max(ProductNr) for Location in([1],[2],[3],[4])) pvt 
; 
+0

你好戴夫 你的回答完美。問題是你會推薦我使用你的代碼而不是我的嗎? – MishMish

+0

@MishMish我*想*它會執行你的多個'全外部JOIN's,雖然這是爲了讓你測試你自己的環境,並從那裏去。 – iamdave

+0

好吧謝謝:) – MishMish

1

其實,我認爲這可能是一個少許清潔劑,然後我想指出的條件聚集的變化如果ProductNRMAX(date)有多個記錄,iamdave的技術獲得MostRecent記錄的結果會產生多於1個結果。我意識到這可能不可能在你的數據集中,這可能會讓其他人閱讀這篇文章。出於這個原因,我建議使用ROW_NUMBER()來確定你想要的記錄,如果你確實想要這些關係,那麼使用RANK()DENSE_RANK()

如果您不希望聯繫我認爲你可以簡化,只是像這樣的東西去:

;WITH cteRowNums AS (
    SELECT 
     Location 
     ,ProductNR 
     ,RowNumber = ROW_NUMBER() OVER (PARTITION BY ProductNR ORDER BY Date DESC) 
    FROM 
     LocationsTest 
) 

SELECT DISTINCT 
    Location1 = CASE WHEN Location = 1 THEN ProductNR END 
    ,Location2 = CASE WHEN Location = 2 THEN ProductNR END 
    ,Location3 = CASE WHEN Location = 3 THEN ProductNR END 
    ,Location4 = CASE WHEN Location = 4 THEN ProductNR END 
FROM  
    cteRowNums 
WHERE 
    RowNumber = 1 

如果你想聯繫,它只是成爲真正有條件聚集如下:

;WITH cteRowNums AS (
    SELECT DISTINCT 
     Location 
     ,ProductNR 
     ,RowNumber = RANK() OVER (PARTITION BY ProductNR ORDER BY Date DESC) 
    FROM 
     LocationsTest 
) 

SELECT 
    Location1 = MAX(CASE WHEN Location = 1 THEN ProductNR END) 
    ,Location2 = MAX(CASE WHEN Location = 2 THEN ProductNR END) 
    ,Location3 = MAX(CASE WHEN Location = 3 THEN ProductNR END) 
    ,Location4 = MAX(CASE WHEN Location = 4 THEN ProductNR END) 
FROM  
    cteRowNums 
WHERE 
    RowNumber = 1 
GROUP BY 
    ProductNR 

然後使用iamdave的方法,你可以做幾乎同樣的事情只能用ROW_NUMBER()RANK()找出你想要的東西如下:

;WITH cteRowNums AS (
    SELECT 
     Location = 'Location' + CAST(Location AS VARCHAR(10)) 
     ,ProductNR 
     ,RowNumber = ROW_NUMBER() OVER (PARTITION BY ProductNR ORDER BY Date DESC) 
    FROM 
     LocationsTest 
) 

, cteDesiredRecords AS (
    SELECT 
     Location 
     ,ProductNR 
     ,ProductNR2 = ProductNR 
    FROM  
     cteRowNums 
    WHERE 
     RowNumber = 1 
) 

SELECT * 
FROM 
    cteDesiredRecords 
    PIVOT (
     MAX(ProductNR) 
     FOR Location IN ([Location1],[Location2],[Location3],[Location4]) 
    ) p 

底線是,PIVOT是一個很棒的命令,但有時它需要一點準備與你的記錄集按摩它做你想做的。在這些情況下,您可以考慮Conditional Aggregation作爲潛在的選擇。

+0

嗨馬特,謝謝你,我會給你的答案一個也是:) – MishMish

相關問題