2016-11-24 97 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

相关问题