我有一个SQL Server表,其中包含与各种Measurement
s相关的几个不同Attribute
的增量Object
:
MeasurementID ObjectID Attribute1 Attribute2 Attribute3
100 1 'blue' 111 'large'
101 1 'blue' 114 'large'
102 1 'red' 114 'large'
103 1 'red' 117 'large'
104 1 'cyan' 118 'large'
105 2 'blue' 450 'huge'
106 3 'blue' 450 'huge'
107 3 'red' 450 'huge'
我的目标是找到一个有效的查询,给定一个特定的ObjectID
告诉我哪些属性发生了变化。例如,让我们说ObjectID=1
。 Attribute1
MeasurementID=102
(从'blue'
更改为'red'
)Attribute2
更改MeasurementID=101
MeasurementID=103
和Attribute3
更改为NULL
CREATE FUNCTION GetMeasurementChanges (ObjectID int, AttributeName varchar)
RETURNS @returnMeasurementIDs TABLE
(MeasurementID int) -- rows of MeasurementIDs
时间Object
。Object
。从概念上讲,我正在寻找符合这种伪代码定义的东西:
Attribute
我可以通过在{{1}} - by - {{1}}基础上选择临时表然后遍历行,测试每个{{1但是我怀疑它的表现非常糟糕。
任何人都可以指点我的技巧或类似问题吗?
谢谢!
答案 0 :(得分:3)
试试这个
if (@attributeName = 'Attribute1')
begin
insert into @returnMeasurementIDs
select measurementid from (
select measurementid,
rank() over (partition by objectId, attribute1 order by measurementid) rnk,
row_number() over (order by measurementid) rn
from table where objectid = @ObjectID
) v where rnk = 1 and rn <> 1
end
else if (@attributeName = 'Attribute2')
begin
insert into @returnMeasurementIDs
select measurementid from (
select measurementid,
rank() over (partition by objectId, attribute2 order by measurementid) rnk,
row_number() over (order by measurementid) rn
from table where objectid = @ObjectID
) v where rnk = 1 and rn <> 1
end
else if (@attributeName = 'Attribute3')
begin
insert into @returnMeasurementIDs
select measurementid from (
select measurementid,
rank() over (partition by objectId, attribute3 order by measurementid) rnk,
row_number() over (order by measurementid) rn
from table where objectid = @ObjectID
) v where rnk = 1 and rn <> 1
end
Rank - 用于按objectid和属性对每个组进行排名,当属性发生变化时,它将返回1。
Row_Number用于对所有行进行排名,并忽略所有已更改的测量ID列表中的第一行,以便返回行102,104等。
答案 1 :(得分:1)
CREATE FUNCTION dbo.GetMeasurementChanges -- always use schema prefix
(
@ObjectID INT, @AttributeName VARCHAR(32)
)
RETURNS TABLE -- use an inline table-valued function when possible
WITH SCHEMABINDING
AS
RETURN
(
WITH x AS
(
SELECT ObjectID, MeasurementID, Attribute1, Attribute2, Attribute3,
rn = ROW_NUMBER() OVER (ORDER BY MeasurementID)
FROM dbo.MyTable -- update this of course
WHERE ObjectID = @ObjectID
), y AS
(
SELECT MeasurementID,
r1 = CASE @AttributeName WHEN 'Attribute1' THEN ROW_NUMBER()
OVER (PARTITION BY Attribute1 ORDER BY MeasurementID) END,
r2 = CASE @AttributeName WHEN 'Attribute2' THEN ROW_NUMBER()
OVER (PARTITION BY Attribute2 ORDER BY MeasurementID) END,
r3 = CASE @AttributeName WHEN 'Attribute3' THEN ROW_NUMBER()
OVER (PARTITION BY Attribute3 ORDER BY MeasurementID) END
FROM x
)
SELECT MeasurementID FROM y WHERE 1 IN (r1, r2, r3)
AND NOT EXISTS
(
SELECT 1 FROM x WHERE x.rn = 1
AND MeasurementID = y.MeasurementID
)
);
GO
替代方案:
CREATE FUNCTION dbo.GetMeasurementChanges -- always use schema prefix
(
@ObjectID INT,
@AttributeName VARCHAR(32)
)
RETURNS TABLE -- use an inline table-valued function when possible
WITH SCHEMABINDING
AS
RETURN
(
WITH x AS
(
SELECT ObjectID, MeasurementID, Attribute1, Attribute2, Attribute3,
rn = ROW_NUMBER() OVER (ORDER BY MeasurementID)
FROM dbo.MyTable WHERE ObjectID = @ObjectID
),
y AS
(
SELECT MeasurementID, r = ROW_NUMBER() OVER (
PARTITION BY CASE @AttributeName
WHEN 'Attribute1' THEN Attribute1
WHEN 'Attribute2' THEN CONVERT(VARCHAR(32), Attribute2)
WHEN 'Attribute3' THEN Attribute3 END
ORDER BY MeasurementID)
FROM x
)
SELECT MeasurementID FROM y WHERE r = 1
AND NOT EXISTS
(
SELECT 1 FROM x WHERE x.rn = 1
AND MeasurementID = y.MeasurementID
)
);
GO
答案 2 :(得分:0)
试试这个
SELECT CASE WHEN a.Attribute1 = b.Attribute1 THEN 1 END AS Attribute1,
CASE WHEN a.Attribute2 = b.Attribute2 THEN 1 END AS Attribute2,
CASE WHEN a.Attribute3 = b.Attribute3 THEN 1 END AS Attribute3
FROM Measurements a
INNER JOIN Measurements b
ON (b.MeasurementID = (SELECT MAX(MeasurementID) FROM Measurements c WHERE c.MeasurementID < a.MeasurementID AND c.ObjectID = a.ObjectID))
答案 3 :(得分:0)
使用选项TOP 1 + CROSS APPLY运算符
CREATE FUNCTION dbo.getMeasurementChanges(@ObjectID int, @AttributeName nvarchar(10))
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT o.MeasurementID
FROM dbo.test90 t
CROSS APPLY (
SELECT TOP 1 MeasurementID, ObjectID,
CASE @AttributeName WHEN 'Attribute1' THEN t.Attribute1
WHEN 'Attribute2' THEN CAST(t.Attribute2 AS nvarchar(10))
WHEN 'Attribute3' THEN t.Attribute3 END AS t1Attributes,
CASE @AttributeName WHEN 'Attribute1' THEN t2.Attribute1
WHEN 'Attribute2' THEN CAST(t2.Attribute2 AS nvarchar(10))
WHEN 'Attribute3' THEN t2.Attribute3 END AS t2Attributes
FROM dbo.test90 t2
WHERE t2.ObjectID = @ObjectID AND t.MeasurementID < t2.MeasurementID
ORDER BY MeasurementID ASC
) o
WHERE t.ObjectID = @ObjectID AND t1Attributes != t2Attributes)
为了提高性能,请使用以下索引:
CREATE INDEX x ON dbo.test90(ObjectID) INCLUDE(MeasurementID, Attribute1, Attribute2, Attribute3)
CREATE INDEX x2 ON dbo.test90(MeasurementID) INCLUDE(ObjectID, Attribute1, Attribute2, Attribute3)
SQLFiddle上的演示