Sql server 如何在此场景中使用交叉应用
我有一个ProductStatus表,如下所示。我需要列出所有最新状态为“SU”的产品。除此之外,我还需要列出该产品以前的状态 基于对不同职位的介绍,交叉申请似乎适合这个职位。我做了如下所列的尝试,但没有得到预期的结果 在SQLServer2005中实现这一点而不使用子查询的最佳方法是什么Sql server 如何在此场景中使用交叉应用,sql-server,Sql Server,我有一个ProductStatus表,如下所示。我需要列出所有最新状态为“SU”的产品。除此之外,我还需要列出该产品以前的状态 基于对不同职位的介绍,交叉申请似乎适合这个职位。我做了如下所列的尝试,但没有得到预期的结果 在SQLServer2005中实现这一点而不使用子查询的最佳方法是什么 DECLARE @ProductStatus TABLE (ProductStatusID INT, productCode VARCHAR(5), statusCode VARCHAR(2)) INSE
DECLARE @ProductStatus TABLE (ProductStatusID INT, productCode VARCHAR(5), statusCode VARCHAR(2))
INSERT INTO @ProductStatus
SELECT 1,'10011','RE' --Recevied
UNION
SELECT 2,'10011','SU' --Suspended
UNION
SELECT 3,'10012','IT' -- In Transit
UNION
SELECT 4,'10012','RE' -- Received
UNION
SELECT 10,'10012','PR' -- Produced
UNION
SELECT 12,'10012','SU' -- Suspended
UNION
SELECT 14,'10013','RE' -- Recevied
UNION
SELECT 16,'10014','SU' -- Recevied
UNION
SELECT 18,'10014','RE' -- Recevied
交叉应用尝试
SELECT *
FROM @ProductStatus P
CROSS APPLY
(
SELECT MAX(V.ProductStatusID) as maxVal
FROM @ProductStatus V
WHERE V.ProductCode = P.ProductCode
AND V. ProductStatusID < P.ProductStatusID
GROUP BY V.ProductCode
)ML
WHERE P.statusCode = 'SU'
预期结果
这是一个复杂的解决方案,主要用于说明这可能应该使用行数来完成:
Lijo,我把它组织成一个CTE,这样你就可以看到我是如何发展我的想法的。如果您对这些查询比较熟悉,那么可以将其重构为子查询而不影响其含义
;with MostRecentStatus as (
select
MAX(ProductStatusID) as ProductStatusID,
productCode
from @ProductStatus as p1
group by productCode
)
,MostRecentIsSU as (
select
p2.ProductStatusID,
p2.productCode,
p2.statusCode
from MostRecentStatus as mrs
inner join @ProductStatus as p2
on p2.ProductStatusID = mrs.ProductStatusID
and p2.statusCode = 'SU'
)
select
m.ProductStatusID,
m.productCode,
m.statusCode,
p3.statusCode as PrevStatus,
p3.ProductStatusID as PrevProductStatusID
from MostRecentIsSU as m
left outer join @ProductStatus as p3
on p3.productCode = m.productcode
and p3.ProductStatusID = m.ProductStatusID - 1;
编辑:…这是一个排号版本,对@attila表示敬意
;with InSquence as
(
select
ProductStatusID,
productCode,
statusCode,
ROW_NUMBER() OVER(PARTITION BY productCode ORDER BY ProductStatusID desc) as Sequence
from @ProductStatus
)
,FirstIsSU as
(
select
ProductStatusID,
productCode
from InSquence
where Sequence = 1
and statusCode = 'SU'
)
,PreviousCode as
(
select
ProductStatusID,
productCode,
statusCode
from InSquence
where Sequence = 2
)
select
f.ProductStatusID,
f.productCode,
'SU' as CurrentStatus,
p.statusCode as PrevStatus,
p.ProductStatusID as PrevProductStatusID
from FirstIsSU as f
left outer join PreviousCode as p
on p.productCode = f.ProductCode;
您可以通过交叉应用来实现这一点,但我认为行数是一种更简单的方法:
select ProductCode,
max(case when seqnum = 1 then statusCode end) as LastStatus,
max(case when seqnum = 2 then statusCode end) as PrevStatus
from (select p.*,
row_number() over (partition by ProductCode order by ProductStatusId desc) as seqnum
from @ProductStatus p
) p
group by ProductCode
having max(case when seqnum = 1 then statusCode end) = 'SU';
使用函数时通常需要交叉应用。我在这里看不到任何功能。当您希望为每一行的组合创建一个叉积时,可以使用交叉联接,在您的示例中,9x9=81行。我再次认为没有理由这样做。简言之,忘记交叉任何东西。@electricalma是的。ProductStatusID是用于查找上一个的列。关于。。。在productstatusid desc排序的产品id中添加一个行号窗口函数,然后选择行号=1和状态=SU的位置,加入行号=2和产品id。实际上我看到10014不应该出现在结果中,因为它最新的不是SU,而是RE。是吗?是的,结果中不应该有“10014”。你知道,进一步看数据,我的解决方案完全不正确!如果@Atilla没有给出答案,我将使用他的建议。我已经修改了我的答案,因此它确实产生了正确的结果,尽管没有使用我们无法依赖的行号和p3.ProductStatusID=m.ProductStatusID-1;中间可能有其他产品数据。。我已经用这个场景更新了这个问题
select ProductCode,
max(case when seqnum = 1 then statusCode end) as LastStatus,
max(case when seqnum = 2 then statusCode end) as PrevStatus
from (select p.*,
row_number() over (partition by ProductCode order by ProductStatusId desc) as seqnum
from @ProductStatus p
) p
group by ProductCode
having max(case when seqnum = 1 then statusCode end) = 'SU';