как я могу сделать этот процесс лучше? - PullRequest
1 голос
/ 20 января 2011

Я хочу знать, как я могу переписать этот SQL в один выбор, используя соединения. У меня есть долгий путь, как показано ниже, чтобы получить минимальную дату «этапа начала проекта» и максимальную дату для этапа «начала производства».

Некоторым фоном является sql для приложения управления проектами, которое отслеживает этапы проектов на основе базового набора релизов. Мне нужно иметь процесс, который берет CSV-список идентификаторов проекта и выбирает минимальную начальную дату для начального этапа проекта (StatusCode.cid = 37) и максимальный промежуточный период производства (StatusCode.cid = 77)

вот мой фиктивный 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]

1 Ответ

3 голосов
/ 20 января 2011

Следует обратить внимание на две вещи, во-первых, вы можете уменьшить 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, ','))  

Нет никакого способа объединить эти два набора, поэтому нет смысла пытаться.Но вы можете объединить два результата в одну строку, чтобы получить все 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

Но поскольку вы используете ISNULL для двух пар, может быть лучше сохранить целевые значения 4Индекс-умеет выбирать и просто подзапрашивать их.Поскольку вы используете значения SPLIT 4 раза, имеет смысл кэшировать их во временной таблице.ISNULL должен быть достаточно умен, чтобы не нуждаться в оценке 2-го выбора, когда первое возвращает значение.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...