INSERT INTO T_PROJECTGROUPSDATA (uploadID, fieldA,fieldB,......fieldN )
SELECT t.ID,p.fieldA,mg.fieldB,......mgc.fieldN
FROM T_Projects mp
INNER JOIN T_UPLOADS t mp.ID = t.project_savix_ID
INNER JOIN SG_Dynamic_Forms..v_projects p ON p.LegacyProjectId = mp.ID
INNER JOIN Savix_Service_Group..Groups mg ON mg.Grp_Project = p.ProjectID
INNER JOIN Savix_Service_Group..Group_Cycle mgc ON mgc.Gc_GroupID = mg.Grp_ID
INNER JOIN Savix_Service_Group..Group_Data mgd ON mgd.Gd_CycleID = mgc.Gc_ID
LEFT JOIN Savix_Service_Trainers..Trainers me ON me.Tr_ID = mgc.Gc_MonitoredBy
LEFT JOIN Savix_Service_Dictionaries..Dictionary mgt ON mgt.Dny_ID = me.Tr_Type
WHERE mp.SyncMode = 1
AND t.[STATUS] = 3 AND t.UPLOADFILENAME = 'Automatic upload from web MIS'
AND mg.Grp_IsDeleted = 0 AND mgd.Gd_IsDeleted != 1
UPDATE t SET
TOTALEXPENDITURES = CASE WHEN DATEDIFF(d,mp.PROJECTESTABLISHEDDATE,mp.EndDate) != 0
THEN p.Cost_Until_Today*DATEDIFF(d,mp.PROJECTESTABLISHEDDATE,dbo.fn_GetEndOfPeriod(t.Period_ID))/DATEDIFF(d,mp.PROJECTESTABLISHEDDATE,mp.EndDate)/dbo.fn_RateAtDate(p.PROJECTCURRENCY_ID,dbo.fn_GetEndOfPeriod(t.Period_ID))
ELSE 0
END,
TotalExpendituresNative = CASE WHEN DATEDIFF(d,mp.PROJECTESTABLISHEDDATE,mp.EndDate) != 0
THEN p.Cost_Until_Today*DATEDIFF(d,mp.PROJECTESTABLISHEDDATE,dbo.fn_GetEndOfPeriod(t.Period_ID))/DATEDIFF(d,mp.PROJECTESTABLISHEDDATE,mp.EndDate)
ELSE 0
END
FROM T_UPLOADS t
JOIN T_Projects mp ON mp.ID = t.project_savix_ID AND mp.SyncMode = 1
WHERE t.[STATUS] = 3 AND t.UPLOADFILENAME = 'Automatic upload from web MIS'
Để giải thích cách tôi nghĩ ra điều này, đây là phiên bản sửa đổi của mã bên dưới. Tôi không thể đảm bảo rằng tôi đã có tất cả mọi thứ, tôi phải đưa ra một số giả định. Thiếu dữ liệu mẫu và thiếu tất cả các bảng savix. Đây là câu trả lời tốt nhất mà tôi có thể đưa ra với thông tin và giới hạn thời gian đầu tư của tôi dưới 4 giờ. Tôi có thể làm được nhiều hơn thế nhưng bạn sẽ phải cho tôi nhiều thứ hơn là sự nổi tiếng trên internet.
--ALTER PROCEDURE [dbo].[proc_Upload] WITH RECOMPILE
--as
set NoCount on
DECLARE
@StartTime datetime,
@EndTime datetime,
@DataID uniqueidentifier,
@CollectionDate datetime,
@Status int,
@PeriodID int,
@EndDate datetime,
@GroupID uniqueidentifier,
@ProjectID INT,
@FAID uniqueidentifier,
@UploadID int ,
@Createdate datetime,
@MINIDprojects INT,
@MAXIDprojects INT,
@MINIDdatasets INT,
@MAXIDdatasets INT,
@MINIDperiods INT,
@MAXIDperiods INT
Rất khó để làm việc và kiểm tra con trỏ, vì vậy tôi đã thay thế chúng (dự án, dự án1, bộ dữ liệu và thời gian) bằng bảng tạm thời có chứa danh tính và lặp qua chúng.
IF OBJECT_ID('tempdb..#projects') IS NOT NULL DROP TABLE #projects
IF OBJECT_ID('tempdb..#projects1') IS NOT NULL DROP TABLE #projects1
IF OBJECT_ID('tempdb..#datasets') IS NOT NULL DROP TABLE #datasets
IF OBJECT_ID('tempdb..#period') IS NOT NULL DROP TABLE #period
CREATE TABLE #projects
(
[ProjectID] [INT],
[Title] [varchar](255) ,
[currency] [int] ,
[Cost_Until_Today] [float] ,
[StartDate] [datetime] ,
[EndDate] [datetime] ,
[MisID] [uniqueidentifier] ,
[SystemStatus] [int] ,
[FacilitatingAgency] [uniqueidentifier] ,
[SyncMode] [int]
)
CREATE TABLE #projects1
(
ID INT IDENTITY(1,1),
[ProjectID] [INT],
[FacilitatingAgency] [uniqueidentifier]
)
CREATE TABLE #datasets
(
ID INT IDENTITY(1,1),
Gd_ID [uniqueidentifier],
Grp_ID [uniqueidentifier],
Gd_CollectionDate DATETIME,
Gd_IsDeleted BIT,
Gd_CreateDate DATETIME
)
CREATE TABLE #period
(
ID INT IDENTITY(1,1),
IDPeriod INT,
EndDate DATETIME
)
INSERT #projects ( [ProjectID], [Title], {currency], [Cost_Until_Today], [StartDate], [EndDate], [MisID], [SystemStatus], [FacilitatingAgency], [SyncMode] )
SELECT ID, PROJECTNAME, PROJECTCURRENCY_ID, Cost_Until_Today, PROJECTESTABLISHEDDATE, EndDate, MisID, 4, FacilitatingAgency, SyncMode
FROM [dbo].[T_PROJECTS] /*thsi is the source table where every projectIDs need to be processed*/
Dự án chứa tất cả ID (projectID) từ T_Projects, các trường duy nhất được sử dụng từ bảng này là ID, tiền tệ dự án, ngày dự án (startdate), ngày kết thúc và mã đồng bộ (phải =1, chúng ta sẽ thấy điều đó sau). Chúng ta có thể bỏ qua systemstatus vì nó là một hằng số.
Bảng dastasets được thả và tải ở đây. Chúng tôi chỉ quan tâm đến gd_id từ bảng Savix_Service_Group..Group_Data nhưng vẫn cần kết hợp với các bảng khác trong trường hợp chúng lọc ra các giá trị mà chúng tôi không muốn. Logic này được sử dụng lại bên dưới khi chèn các bản ghi.
IF exists ( select * from dbo.sysobjects where id = object_id(N'[dbo].datasets]') and objectproperty(id, N'IsTable') = 1 ) DROP Table [dbo].datasets
SELECT mgd.Gd_ID, mg.Grp_ID, mgd.Gd_CollectionDate, mgd.Gd_IsDeleted, mgd.Gd_CreateDate, mg.Grp_Project, mg.Grp_IsDeleted , mg.Grp_Legacy_ID, p.LegacyProjectId
INTO datasets
FROM Savix_Service_Group..Group_Data mgd
INNER JOIN Savix_Service_Group..Group_Cycle mgc ON mgc.Gc_ID = mgd.Gd_CycleID
INNER JOIN Savix_Service_Group..Groups mg ON mg.Grp_ID = mgc.Gc_GroupID
inner join SG_Dynamic_Forms..v_projects p ON p.ProjectID = mg.Grp_Project
--DECLARE projects1 CURSOR LOCAL FOR Select distinct ProjectID, isnull([FacilitatingAgency], '00000000-0000-0000-0000-000000000000') from @projects P WHERE P.SystemStatus = 4 AND P.SyncMode = 1
--/*First cursor - fetch the cursor from ProjectaTable*/
--OPEN projects1
--FETCH NEXT FROM projects1 INTO @ProjectID, @FAID
--WHILE @@FETCH_STATUS = 0
Ở đây chúng tôi đang chèn vào các dự án1 một giá trị khác biệt của id dự án. Nếu không có thêm dữ liệu, giả định của tôi là ID khác biệt trong bảng T_projects và do đó bước này hơi không cần thiết ngoài việc lọc ra bởi SyncMode =1. Hãy nhớ rằng SystemStatus là một hằng số và chúng tôi đã điền nó với giá trị '4', điều này tiêu chí có thể bị xóa mà không có hiệu lực.
INSERT INTO #projects1 ( ProjectID, FacilitatingAgency )
SELECT DISTINCT ProjectID, isnull([FacilitatingAgency], '00000000-0000-0000-0000-000000000000')
FROM #projects p
WHERE SystemStatus = 4 AND SyncMode = 1
SELECT @MINIDprojects = MIN(ID), @MAXIDprojects = MAX(ID) FROM #projects1
WHILE @MINIDprojects < @MAXIDprojects + 1
BEGIN
-- BEGIN TRY
-- BEGIN TRAN
SELECT @ProjectID = ProjectID, @FAID = FacilitatingAgency FROM #projects1 WHERE ID = @MINIDprojects
--DELETE FROM T_PROJECTGROUPSDATA WHERE T_PROJECTGROUPSDATA.UPLOAD_ID IN (SELECT ID FROM T_UPLOADS WHERE project_savix_ID = @ProjectID AND UPLOADFILENAME = 'Automatic upload from web MIS')
--DECLARE datasets CURSOR LOCAL FAST_FORWARD FOR SELECT Gd_ID, Grp_ID, Gd_CollectionDate, Gd_IsDeleted, Gd_CreateDate
-- FROM datasets
-- WHERE LegacyProjectId = @ProjectID AND Grp_IsDeleted = 0 AND Gd_IsDeleted != 1
-- /*Second cursor - this will get the 'collectionDate'field from datasetsTable for every project fetched in above cursor and also get @dataID which is used to insert value in to other table-T_PROJECTGROUPSDATA*/
--OPEN datasets
--FETCH NEXT FROM datasets INTO @DataID, @GroupID, @CollectionDate, @Status, @Createdate
--WHILE @@FETCH_STATUS = 0
Ở đây chúng tôi chèn vào #datasets lọc theo T_Project.ID VÀ Savix_Service_Group..Groups.Grp_IsDeleted =0 AND Savix_Service_Group..Group_Data.Gd_IsDeleted! =1
INSERT INTO #datasets ( Gd_ID, Grp_ID, Gd_CollectionDate, Gd_IsDeleted, Gd_CreateDate )
SELECT Gd_ID, Grp_ID, Gd_CollectionDate, Gd_IsDeleted, Gd_CreateDate FROM datasets WHERE LegacyProjectId = @ProjectID AND Grp_IsDeleted = 0 AND Gd_IsDeleted != 1
SELECT @MINIDdatasets = MIN(ID), @MAXIDdatasets = MAX(ID) FROM #datasets
WHILE @MINIDdatasets < @MAXIDdatasets + 1
BEGIN
SELECT @DataID = Gd_ID, @GroupID = Grp_ID, @CollectionDate = Gd_CollectionDate, @Status = Gd_IsDeleted, @Createdate = Gd_CreateDate FROM #datasets WHERE ID = @MINIDdatasets
--DECLARE period CURSOR LOCAL FAST_FORWARD FOR SELECT ID, dbo.fn_GetEndOfPeriod(ID) FROM T_PERIODS
--/* dbo.fn_GetEndOfPeriod(ID) - this function will give the end of the date of that specifc quarter for any given date*/
-- WHERE DATEDIFF(dd,@CollectionDate,dbo.fn_GetEndOfPeriod(ID)) >= 0
-- ORDER BY [YEAR],[Quarter]
-- /*Third Cursor - this will process the records from another table called period with above fetched @collectionDate*/
--OPEN period
--FETCH NEXT FROM period INTO @PeriodID, @EndDate
--WHILE @@FETCH_STATUS = 0
Đây có lẽ là cách sử dụng con trỏ tồi tệ nhất ở đây. Chúng tôi tải tất cả các khoảng thời gian và chuyển qua chúng. Cuối cùng, chúng tôi chỉ quan tâm đến các khoảng thời gian có trong bảng T_UPLOADS.
INSERT INTO #period ( IDPeriod, EndDate ) SELECT ID, dbo.fn_GetEndOfPeriod(ID) FROM T_PERIODS WHERE DATEDIFF(dd,@CollectionDate,dbo.fn_GetEndOfPeriod(ID)) >= 0
SELECT @MINIDperiods = MIN(ID), @MAXIDperiods = MAX(ID) FROM #period
WHILE @MINIDperiods < @MAXIDperiods + 1
BEGIN
--IF EXISTS (SELECT * FROM Savix_Service_Group..Group_Data mgd
-- INNER JOIN Savix_Service_Group..Group_Cycle mgc ON mgc.Gc_ID = mgd.Gd_CycleID
-- WHERE mgc.Gc_GroupID = @GroupID
-- AND DATEDIFF(dd,mgd.Gd_CollectionDate,@EndDate) >= 0
-- AND (mgd.Gd_CollectionDate > @CollectionDate )
-- AND mgd.Gd_IsDeleted != 1)
--BEGIN
-- BREAK
--END
Ở đây, chúng tôi bỏ qua bất kỳ khoảng thời gian nào mà UPLOADFILENAME! ='Tải lên tự động từ web MIS'
--IF EXISTS (SELECT ID FROM T_UPLOADS u WHERE u.project_savix_ID = @ProjectID AND u.PERIOD_ID = @PeriodID AND u.STATUS = 3 AND UPLOADFILENAME != 'Automatic upload from web MIS')
--BEGIN
-- FETCH NEXT FROM period INTO @PeriodID, @EndDate
-- CONTINUE
--END
Với ý nghĩ đó, chúng tôi chỉ quan tâm đến nơi status =3 và UPLOADFILENAME ='Tải lên tự động từ web MIS'
SET @UploadID = (SELECT ID FROM T_UPLOADS u WHERE u.project_savix_ID = @ProjectID AND u.PERIOD_ID = @PeriodID AND u.[STATUS] = 3 AND UPLOADFILENAME = 'Automatic upload from web MIS')
/*If T_uploads doesn't have appropirate period ID from cursor fetch then create a new entry in T_uploads with current projectID*/
IF @UploadID IS NOT NULL
BEGIN
--declare @Project_ID_Legacy int = ISNULL((select distinct PROJECT_ID from T_UPLOADS where project_savix_ID = @ProjectID),@ProjectID)
Tại sao họ sử dụng bảng thứ hai (T_UPLOADFIRSTSTEP) để tạo một bản ghi trong đó họ chỉ sử dụng id và sau đó xóa bản ghi bằng cách sử dụng ID đó trong quá trình tạo bản ghi T_Uploads là điều tôi không hiểu và dường như tôi là một mã hóa tồi tệ.
-- INSERT INTO T_UPLOADSFIRSTSTEP
-- (PROJECT_ID
-- --,UPLOADDATE
-- --,UPLOADFILENAME
-- --,UPLOADUSER_ID
-- --,CURRENTSTEP
-- ,[STATUS]
-- ,Project_ID_MIS)
-- SELECT ISNULL((select distinct PROJECT_ID from T_UPLOADS where project_savix_ID = @ProjectID),@ProjectID),
-- --GETDATE(),
-- --'Automatic upload from web MIS',
-- --2,
-- --2,
-- 0,
-- @ProjectID
Chèn vào T_UPLOADS sẽ luôn không thành công vì có các trường không được rỗng không có trong danh sách chèn và không được gán giá trị mặc định cho chúng.
-- INSERT INTO T_UPLOADS ( ID, periodID, projectID,UPLOADDATE,UPLOADFILENAME,UPLOADUSER_ID )
-- SELECT uf.ID,
-- @PeriodID,
-- ISNULL((select distinct PROJECT_ID from T_UPLOADS where project_savix_ID = @ProjectID),@ProjectID),
-- GETDATE(),
-- 'Automatic upload from web MIS',
-- 2
-- FROM T_UPLOADSFIRSTSTEP uf
-- INNER JOIN #projects mp ON uf.Project_ID_MIS = mp.ProjectID
-- WHERE uf.Project_ID_MIS = @ProjectID AND uf.[STATUS] = 0
-- AND NOT EXISTS (SELECT * FROM T_UPLOADS u WHERE u.PROJECT_ID = uf.PROJECT_ID AND u.PERIOD_ID = @PeriodID AND u.[STATUS] = 3)
-- DELETE FROM T_UPLOADSFIRSTSTEP WHERE STATUS = 0 AND PROJECT_ID = ISNULL((select distinct PROJECT_ID from T_UPLOADS where project_savix_ID = @ProjectID),@ProjectID)
-- --SET @UploadID = (SELECT ID FROM T_UPLOADS u WHERE u.project_savix_ID = @ProjectID AND u.PERIOD_ID = @PeriodID AND u.[STATUS] = 3)
-- END
--ELSE
Vì vậy, đây là logic thực sự được thực hiện bên trong 3 con trỏ đó. Hiểu rằng chúng ta không quan tâm đến các chu kỳ, logic lặp lại tất cả chúng. Chúng tôi chỉ quan tâm rằng chúng tôi phải lọc các tiêu chí nhất định (status =3 và UPLOADFILENAME ='Tải lên tự động từ web MIS') và chúng có bảng T_Project.ID phù hợp với tiêu chí T_Projects.SyncMode =1
UPDATE t SET
TOTALEXPENDITURES = CASE WHEN DATEDIFF(d,mp.StartDate,mp.EndDate) != 0
THEN mp.Cost_Until_Today*DATEDIFF(d,mp.StartDate,dbo.fn_GetEndOfPeriod(t.Period_ID))/DATEDIFF(d,mp.StartDate,mp.EndDate)/dbo.fn_RateAtDate(mp.Currency,dbo.fn_GetEndOfPeriod(t.Period_ID))
ELSE 0
END,
TotalExpendituresNative = CASE WHEN DATEDIFF(d,mp.StartDate,mp.EndDate) != 0
THEN mp.Cost_Until_Today*DATEDIFF(d,mp.StartDate,dbo.fn_GetEndOfPeriod(t.Period_ID))/DATEDIFF(d,mp.StartDate,mp.EndDate)
ELSE 0
END
FROM T_UPLOADS t
JOIN #projects mp ON mp.ProjectID = t.project_savix_ID
WHERE 1=1 -- t.ID = @UploadID
--AND t.project_savix_ID = @ProjectID AND t.PERIOD_ID = @PeriodID
AND t.[STATUS] = 3 AND t.UPLOADFILENAME = 'Automatic upload from web MIS'
Chèn vào T_PROJECTGROUPDATA đã sao chép logic được sử dụng để tạo biến @dataid có nguồn gốc từ #datasets. Điều này có nguồn gốc từ bảng bộ dữ liệu mà chúng tôi đã bỏ và tạo ở trên.
INSERT INTO T_PROJECTGROUPSDATA (uploadID, fieldA,fieldB,......fieldN )
SELECT @UploadID,p.fieldA,mg.fieldB,......mgc.fieldN
FROM #projects mp
inner join SG_Dynamic_Forms..v_projects p ON p.LegacyProjectId = mp.projectID
inner join Savix_Service_Group..Groups mg ON mg.Grp_Project = p.ProjectID
INNER JOIN Savix_Service_Group..Group_Cycle mgc ON mgc.Gc_GroupID = mg.Grp_ID
INNER JOIN Savix_Service_Group..Group_Data mgd ON mgd.Gd_CycleID = mgc.Gc_ID
LEFT JOIN Savix_Service_Trainers..Trainers me ON me.Tr_ID = mgc.Gc_MonitoredBy
LEFT JOIN Savix_Service_Dictionaries..Dictionary mgt ON mgt.Dny_ID = me.Tr_Type
--left join v1_Report_UDF_Data_UploadToSavix udf on udf.DataID = mgd.Gd_ID
WHERE mgd.Gd_ID = @DataID
--FETCH NEXT FROM period INTO @PeriodID, @EndDate
SET @MINIDperiods = @MINIDperiods + 1
END
--CLOSE period
--DEALLOCATE period
--FETCH NEXT FROM datasets INTO @DataID, @GroupID, @CollectionDate, @Status, @Createdate
SET @MINIDdatasets = @MINIDdatasets + 1
END
--CLOSE datasets
--DEALLOCATE datasets
--COMMIT
--END TRY
--BEGIN CATCH
--SELECT ERROR_NUMBER(), ERROR_MESSAGE(),@PeriodID, @ProjectID, @UploadID,@DataID
--IF CURSOR_STATUS('global' , 'period') >= 0
--BEGIN
-- CLOSE period
-- DEALLOCATE uploadID
--END
--IF CURSOR_STATUS('global' , 'datasets') >= 0
--BEGIN
-- CLOSE datasets
-- DEALLOCATE datasets
--END
--IF @@TRANCOUNT > 0
-- ROLLBACK
--INSERT INTO error_catch_UploadtoSavix
--SELECT cast(ERROR_NUMBER() as nvarchar), ERROR_MESSAGE(),@PeriodID, @ProjectID, @UploadID,@DataID, getdate()
--END CATCH
SET @MINIDprojects = @MINIDprojects + 1
--FETCH NEXT FROM projects1 INTO @ProjectID, @FAID
END
--CLOSE projects1
--DEALLOCATE projects1
--SELECT 1 as success
Đây là bạn có nó. Cô đọng gần 300 dòng và 3 con trỏ xuống còn 30 dòng và không có con trỏ.