我有一个待处理更改表,我正在尝试将更改应用到视图中,以便查看最新数据。
首先是一些背景:我有一个网站,允许对Project Web Access(PWA)中的数据进行简单的更改。 PWA的一个问题是您无法直接在其数据库中更改数据,因此我使用SharePoint的CSOM来检出,修改,签入,发布和保存对项目和任务的更改。这需要10-20秒,这对于网站上的用户体验来说太慢了。
我通过将修改后的字段写入待处理的更改表来解决这个问题,即行的标识符,字段已更改以及新值。我目前在c#.Net(RBAR)中合并这些更改,以便显示网站。
我想在SQL服务器中合并这些数据,最好不要逐行合并。
我正在这里测试
WITH
SourceDataView (id, name, age, joined) AS
(
SELECT 1, 'John' , 45, Cast('2018-01-15' as DateTime) UNION
SELECT 2, 'Paul', 33, Cast('2018-02-08' as DateTime) UNION
SELECT 3, 'George', 39, Cast('2018-03-29' as DateTime)
),
PendingChanges (id, foreignId, fieldName, fieldValue) AS
(
SELECT 1, 2, 'name', 'Peter' UNION
SELECT 2, 1, 'age', '34' UNION
SELECT 3, 3, 'joined', '2018-02-22' UNION
SELECT 4, 1, 'joined', '2018-01-10' UNION
SELECT 5, 3, 'joined', '2017-12-30'
)
-- Just show the joined data
SELECT * FROM
SourceDataView s
LEFT JOIN
PendingChanges p
on s.id = p.foreignId
ORDER BY p.id;
-- This is what I am expecting
WITH
DesiredResultsView (id, name, age, joined) AS (
SELECT 1, 'John' , 34, Cast('2018-01-10' as DateTime) UNION
SELECT 2, 'Peter', 33, Cast('2018-02-08' as DateTime) UNION
SELECT 3, 'George', 39, Cast('2017-12-30' as DateTime)
) SELECT * from DesiredResultsView
如果数据在上次编辑中获得两次更改,则需要注意几点。此外,数据类型需要正确转换。
答案 0 :(得分:0)
而不是尝试使用PendingChanges格式的SourceDataView Work格式的数据:
要首先对源进行UNPIVOT,然后您将能够将更改与简单的UNION合并。然后对每行的更改进行编号,并仅保留每个字段的最新版本。最后将数据PIVOT回到所需的形状并重新应用原始数据类型。
WITH
SourceDataView (id, name, age, joined) AS
(
SELECT 1, 'John' , 45, Cast('2018-01-15' as DateTime) UNION
SELECT 2, 'Paul', 33, Cast('2018-02-08' as DateTime) UNION
SELECT 3, 'George', 39, Cast('2018-03-29' as DateTime)
),
PendingChanges (id, foreignId, fieldName, fieldValue) AS
(
SELECT 1, 2, 'name', 'Peter' UNION
SELECT 2, 1, 'age', '34' UNION
SELECT 3, 3, 'joined', '2018-02-22' UNION
SELECT 4, 1, 'joined', '2018-01-10' UNION
SELECT 5, 3, 'joined', '2017-12-30'
),
SourceUnpivot (id, foreignId, fieldName, fieldValue) AS
(
SELECT 0 as id, id as foreignId, fieldName, fieldValue
FROM
(SELECT id
, cast(name as sql_variant) name
, cast(age as sql_variant) age
, cast(joined as sql_variant) joined
FROM SourceDataView) p
UNPIVOT
(fieldValue FOR fieldName IN
(name, age, joined)
) AS _SourceUnpivot
),
MergeChanges as
(
SELECT * FROM SourceUnpivot
UNION SELECT * from PendingChanges
),
NumberedChanges as
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY foreignID, fieldName ORDER BY id DESC) as ChangeNumber
from MergeChanges
),
MergePivot as
(
SELECT id,
Cast(name as nvarchar(max)) as name,
Cast(age as int) as age,
Cast(joined as DateTime) as joined
FROM (
SELECT foreignId as id, fieldName, fieldValue
from NumberedChanges
where ChangeNumber = 1
) as LastChangeOnly
PIVOT (
MAX(fieldValue)
FOR fieldName in (name, age, joined)
)
as _MergePivot
)
SELECT * from MergePivot ORDER BY id;
WITH
DesiredResultsView (id, name, age, joined) AS (
SELECT 1, 'John' , 34, Cast('2018-01-10' as DateTime) UNION
SELECT 2, 'Peter', 33, Cast('2018-02-08' as DateTime) UNION
SELECT 3, 'George', 39, Cast('2017-12-30' as DateTime)
) SELECT * from DesiredResultsView
答案 1 :(得分:0)
我认为你可能会发现这个解决方案更简单一点,希望性能也更好一些。
CREATE TABLE SourceDataView
(
ID INT
,[Name] VARCHAR(50)
,Age TINYINT
,Joined DateTime
)
;
CREATE TABLE PendingChanges
(
ID INT
,ForeignID INT
,FieldName VARCHAR(10)
,FieldValue VARCHAR(100)
)
;
INSERT INTO SourceDataView
VALUES
(1, 'John' , 45, '2018-01-15')
,(2, 'Paul', 33, '2018-02-08')
,(3, 'George', 39, '2018-03-29')
;
INSERT INTO PendingChanges
VALUES
(1, 2, 'name', 'Peter')
,(2, 1, 'age', '34' )
,(3, 3, 'joined', '2018-02-22')
,(4, 1, 'joined', '2018-01-10')
,(5, 3, 'joined', '2017-12-30')
;
WITH CTE AS
(
SELECT *
FROM
(
SELECT
ROW_NUMBER() OVER (PARTITION BY ForeignID,FieldName ORDER BY ID DESC) AS ChangeNumber
,*
FROM PendingChanges
) AS RowNum
PIVOT
(
MAX(FieldValue)
FOR FieldName IN ([name],[age],[joined])
) AS P
)
SELECT
SDV.ID
,COALESCE(CA.[name],SDV.[name]) AS [name]
,COALESCE(CA.age,SDV.age) AS age
,COALESCE(CA.joined,SDV.joined) AS joined
FROM SourceDataView AS SDV
CROSS APPLY
(
SELECT
(SELECT [name] FROM CTE WHERE CTE.ForeignID = SDV.ID AND CTE.ChangeNumber = 1 AND CTE.[name] IS NOT NULL) AS [name]
,(SELECT age FROM CTE WHERE CTE.ForeignID = SDV.ID AND CTE.ChangeNumber = 1 AND CTE.age IS NOT NULL) AS age
,(SELECT joined FROM CTE WHERE CTE.ForeignID = SDV.ID AND CTE.ChangeNumber = 1 AND CTE.joined IS NOT NULL) AS joined
) AS CA