2011-01-19 70 views
1

我想知道如何使用連接將此SQL重寫爲單個選擇。我有一個很長的繪製方式,如下所示,以基本獲得「項目啓動里程碑」的最短日期和「生產上線」里程碑的最長日期。我該如何讓這個過程更好?

一些背景是SQL是針對項目管理應用程序的,該項目管理應用程序針對發佈基準里程碑集跟蹤項目里程碑。我需要一個proc,它需要一個projectIDs的CSV列表,並讓它爲項目初始里程碑(StatusCode.cid = 37)和最大生產上線里程碑(StatusCode.cid = 77)選擇min startDate

這裏是我的虛擬SQL我現在有工作:

CREATE PROC rpt_rainbow 
@ProjectIDs NVARCHAR(1000) 
AS 

DECLARE @MinBRSProjectStartDate DATETIME 
DECLARE @MinBRSReleaseStartDate DATETIME 

DECLARE @MaxProdProjectEndDate DATETIME 
DECLARE @MaxProdReleaseEndDate DATETIME 

SELECT @MinBRSProjectStartDate = MIN (pm.startDate) 
FROM StatusCode sc  
INNER JOIN ProjectMilestone pm ON sc.CID = pm.MilestoneCID AND pm.ProjectID IN (SELECT value FROM fn_Split(@ProjectIDs, ',')) 
WHERE sc.cid =37 

SELECT @MinBRSReleaseStartDate = MIN(rel.startDate) 
FROM Project p 
INNER JOIN ReleaseSchedule rel ON rel.ReleaseID = p.ReleaseID AND rel.milestonecid IN (37) 
WHERE ProjectId IN (SELECT value FROM fn_Split(@ProjectIDs, ',')) 

SELECT @MaxProdProjectEndDate = MAX (pm.endDate) 
FROM StatusCode sc  
INNER JOIN ProjectMilestone pm ON sc.CID = pm.MilestoneCID AND pm.ProjectID IN (SELECT value FROM fn_Split(@ProjectIDs, ',')) 
WHERE sc.cid =77 

SELECT @MaxProdReleaseEndDate = MAX(rel.endDate) 
FROM Project p 
INNER JOIN ReleaseSchedule rel ON rel.ReleaseID = p.ReleaseID AND rel.milestonecid IN (77) 
WHERE ProjectId IN (SELECT value FROM fn_Split(@ProjectIDs, ',')) 


select isnull(@MinBRSProjectStartDate, @MinBRSReleaseStartDate) as MinBRS_StartDate, 
    isnull(@MaxProdProjectEndDate, @MaxProdReleaseEndDate) as MaxProd_EndDate 

這裏是我的分裂功能:

CREATE FUNCTION dbo.Split 
    ( @Delimiter varchar(5), 
     @List  varchar(8000) 
    ) 
    RETURNS @TableOfValues table 
     ( RowID smallint IDENTITY(1,1), 
     [Value] varchar(50) 
    ) 
AS 
    BEGIN 

     DECLARE @LenString int 

     WHILE len(@List) > 0 
     BEGIN 

      SELECT @LenString = 
       (CASE charindex(@Delimiter, @List) 
        WHEN 0 THEN len(@List) 
        ELSE (charindex(@Delimiter, @List) -1) 
       END 
       ) 

      INSERT INTO @TableOfValues 
       SELECT substring(@List, 1, @LenString) 

      SELECT @List = 
       (CASE (len(@List) - @LenString) 
        WHEN 0 THEN '' 
        ELSE right(@List, len(@List) - @LenString - 1) 
       END 
       ) 
     END 

     RETURN 

    END 

,這裏是所涉及表的定義:

CREATE TABLE [dbo].[ProjectMilestone](
    [ProjectMilestoneId] [int] NOT NULL, 
    [ProjectId] [int] NOT NULL, 
    [MilestoneCID] [int] NOT NULL, 
    [StartDate] [datetime] NOT NULL, 
    [EndDate] [datetime] NOT NULL, 
    [RAGStatusCID] [int] NOT NULL, 
    [CompletionStatusCID] [int] NOT NULL, 
    [StatusText] [nvarchar](max) NOT NULL, 
    [ReportingPriority] [int] NULL, 
    [Owner] [nvarchar](50) NOT NULL, 
    [Added] [datetime] NOT NULL, 
    [LastUpdate] [datetime] NOT NULL, 
    [UpdateBy] [nvarchar](50) NOT NULL, 
CONSTRAINT [PK_ProjectMilestone] PRIMARY KEY CLUSTERED 
(
    [ProjectMilestoneId] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

GO 
ALTER TABLE [dbo].[ProjectMilestone] WITH CHECK ADD CONSTRAINT [FK_ProjectMilestone_Project] FOREIGN KEY([ProjectId]) 
REFERENCES [dbo].[Project] ([ProjectId]) 
GO 
ALTER TABLE [dbo].[ProjectMilestone] CHECK CONSTRAINT [FK_ProjectMilestone_Project] 


----------------------------------------------------------------------------------------------- 

CREATE TABLE [dbo].[Project](
    [ProjectId] [int] NOT NULL, 
    [ProjectName] [nvarchar](255) NOT NULL, 
    [ProjectRegistration] [nvarchar](50) NOT NULL, 
    [CaseManagerBenId] [nvarchar](50) NOT NULL, 
    [ClarityId] [nvarchar](50) NOT NULL, 
    [ParentProjectId] [int] NULL, 
    [ReleaseId] [int] NOT NULL, 
    [CompletionStatusCID] [int] NOT NULL, 
    [ProjectTypeCID] [int] NOT NULL, 
    [Budget] [money] NOT NULL, 
    [BusinessObjective] [nvarchar](max) NOT NULL, 
    [Benefit] [nvarchar](max) NOT NULL, 
    [Added] [datetime] NOT NULL, 
    [LastUpdate] [datetime] NOT NULL, 
    [UpdateBy] [nvarchar](50) NOT NULL, 
    [StakeholderList] [nvarchar](1000) NULL, 
CONSTRAINT [PK_Project] PRIMARY KEY CLUSTERED 
(
    [ProjectId] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

GO 
ALTER TABLE [dbo].[Project] WITH CHECK ADD CONSTRAINT [FK_Project_Project] FOREIGN KEY([ParentProjectId]) 
REFERENCES [dbo].[Project] ([ProjectId]) 
GO 
ALTER TABLE [dbo].[Project] CHECK CONSTRAINT [FK_Project_Project] 
GO 
ALTER TABLE [dbo].[Project] WITH CHECK ADD CONSTRAINT [FK_Project_Release] FOREIGN KEY([ReleaseId]) 
REFERENCES [dbo].[Release] ([ReleaseId]) 
GO 
ALTER TABLE [dbo].[Project] CHECK CONSTRAINT [FK_Project_Release] 

-------------------------------------------------------------------------------------------- 

CREATE TABLE [dbo].[StatusCode](
    [CID] [int] NOT NULL, 
    [CodeName] [nvarchar](50) NOT NULL, 
    [Description] [nvarchar](max) NOT NULL, 
    [SCID] [int] NOT NULL, 
    [ReportingPriority] [int] NULL, 
CONSTRAINT [PK_StatusCode] PRIMARY KEY CLUSTERED 
(
    [CID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

-------------------------------------------------------------------------------------------- 

CREATE TABLE [dbo].[ReleaseSchedule](
    [ReleaseScheduleID] [int] NOT NULL, 
    [ReleaseID] [int] NOT NULL, 
    [MilestoneCID] [int] NOT NULL, 
    [StartDate] [datetime] NOT NULL, 
    [EndDate] [datetime] NOT NULL, 
    [Added] [datetime] NOT NULL, 
    [LastUpdate] [datetime] NOT NULL, 
    [UpdateBy] [nvarchar](50) NOT NULL, 
CONSTRAINT [PK_ReleaseSchedule] PRIMARY KEY CLUSTERED 
(
    [ReleaseScheduleID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

GO 
ALTER TABLE [dbo].[ReleaseSchedule] WITH CHECK ADD CONSTRAINT [FK_ReleaseSchedule_Release] FOREIGN KEY([ReleaseID]) 
REFERENCES [dbo].[Release] ([ReleaseId]) 
GO 
ALTER TABLE [dbo].[ReleaseSchedule] CHECK CONSTRAINT [FK_ReleaseSchedule_Release] 
+0

你確定它現在「工作」了嗎?你正在用錯誤的方式使用SPLIT(delim/list) – RichardTheKiwi 2011-01-19 23:14:44

+0

我目前的解決方案正在工作,但看起來很笨重,就像大猩猩(我)寫的。 – kacalapy 2011-01-20 04:40:21

回答

3

有值得注意的兩件事情,第一個是,你可以在4個查詢降至2

SELECT 
    @MinBRSProjectStartDate = MIN (CASE WHEN sc.cid=37 then pm.startDate END), 
    @MaxProdProjectEndDate = MAX (CASE WHEN sc.cid=77 then pm.endDate END) 
FROM StatusCode sc  
INNER JOIN ProjectMilestone pm ON sc.CID = pm.MilestoneCID 
    AND pm.ProjectID IN (SELECT value FROM fn_Split(@ProjectIDs, ',')) 
WHERE sc.cid in (37,77) 

SELECT 
    @MinBRSReleaseStartDate = MIN(CASE WHEN rel.milestonecid=37 then rel.startDate end), 
    @MaxProdReleaseEndDate = MAX(CASE WHEN rel.milestonecid=77 then rel.endDate end) 
FROM Project p 
INNER JOIN ReleaseSchedule rel ON rel.ReleaseID = p.ReleaseID AND rel.milestonecid IN (37,77) 
WHERE ProjectId IN (SELECT value FROM fn_Split(@ProjectIDs, ',')) 

實在是沒有辦法這兩組之間的加入,所以沒有一點嘗試。但是你可以CROSS JOIN的兩個單列的結果讓所有的4列在一個單一的選擇:

SELECT ISNULL(A,C) as MinBRS_StartDate, ISNULL(B,D) AS MaxProd_EndDate 
FROM 
( 
SELECT 
    MIN (CASE WHEN sc.cid=37 then pm.startDate END) A, 
    MAX (CASE WHEN sc.cid=77 then pm.endDate END) B 
FROM StatusCode sc  
INNER JOIN ProjectMilestone pm ON sc.CID = pm.MilestoneCID 
    AND pm.ProjectID IN (SELECT value FROM fn_Split(@ProjectIDs, ',')) 
WHERE sc.cid in (37,77) 
) X, 
(
SELECT 
    MIN(CASE WHEN rel.milestonecid=37 then rel.startDate end) C, 
    MAX(CASE WHEN rel.milestonecid=77 then rel.endDate end) D 
FROM Project p 
INNER JOIN ReleaseSchedule rel ON rel.ReleaseID = p.ReleaseID AND rel.milestonecid IN (37,77) 
WHERE ProjectId IN (SELECT value FROM fn_Split(@ProjectIDs, ','))) Y 

但由於使用的是整個2對ISNULL,它可能是更好的保持4針對性首頁 - 能夠選擇並僅僅子查詢它們。由於您使用SPLIT值4次,因此將其緩存在臨時表中是有意義的。 ISNULL應該足夠聰明,無需在第一次返回值時評估第二次選擇。

declare @ids table (id int) 
insert @ids SELECT distinct value FROM fn_Split(',', @ProjectIDs) V 

SELECT 
    ISNULL(
     (SELECT MIN (pm.startDate) 
      FROM StatusCode sc 
      INNER JOIN ProjectMilestone pm ON sc.CID = pm.MilestoneCID 
      INNER JOIN @ids I ON pm.ProjectID = I.ID 
      WHERE sc.cid =37), 
     (SELECT MIN(rel.startDate) 
      FROM Project p 
      INNER JOIN ReleaseSchedule rel ON rel.ReleaseID = p.ReleaseID 
      INNER JOIN @ids I ON p.ProjectID = I.ID 
      WHERE rel.milestonecid IN (37))) AS MinBRS_StartDate, 
    ISNULL(
     (SELECT MAX (pm.endDate) 
      FROM StatusCode sc  
      INNER JOIN ProjectMilestone pm ON sc.CID = pm.MilestoneCID 
      INNER JOIN @ids I ON pm.ProjectID = I.ID 
      WHERE sc.cid =77), 
     (SELECT MAX(rel.endDate) 
      FROM Project p 
      INNER JOIN ReleaseSchedule rel ON rel.ReleaseID = p.ReleaseID 
      INNER JOIN @ids I ON p.ProjectID = I.ID 
      WHERE rel.milestonecid IN (77))) AS MaxProd_EndDate