我的下面代码运行正常。它的作用是在移动到新位置时更新每个产品编号
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 :(得分:1)
我实际上建议使用条件聚合的变体,这可能会更清晰一些,然后我想指出iamdave技术获得MostRecent
记录会产生多于1个结果的细微差别。 ProductNR
有多个MAX(date)
的记录。我意识到你的数据集可能不太可能是其他人阅读帖子。出于这个原因,我建议您使用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
视为潜在替代方案。
答案 1 :(得分: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
;