2015-05-27 19 views
7

Dopo molte modifiche alla procedura memorizzata, ritengo che sia necessario eseguire nuovamente il factoring, principalmente a causa della duplicazione del codice. Come superare queste duplicazioni:Procedura memorizzata: riduzione della duplicazione del codice mediante le tabelle temporanee

IF @transExist > 0 BEGIN 
    IF @transType = 1 BEGIN --INSERT 
     SELECT 
      a.dayDate, 
      a.shiftName, 
      a.limit, 
      b.startTimeBefore, 
      b.endTimeBefore, 
      b.dayAdd, 
      b.name, 
      b.overtimeHours, 
      c.startTime, 
      c.endTime 
     INTO 
      #Residence1 
     FROM 
      #ShiftTrans a 
      RIGHT OUTER JOIN #ResidenceOvertime b 
       ON a.dayDate = b.dayDate 
      INNER JOIN ShiftDetails c 
       ON c.shiftId = a.shiftId AND 
       c.shiftTypeId = b.shiftTypeId; 

     SET @is_trans = 1; 
    END ELSE BEGIN 
     RETURN ; 
    END 
END ELSE BEGIN 
    IF @employeeExist > 0 BEGIN 
     SELECT 
      a.dayDate, 
      a.shiftName, 
      a.limit, 
      b.startTimeBefore, 
      b.endTimeBefore, 
      b.dayAdd, 
      b.name, 
      b.overtimeHours, 
      c.startTime, 
      c.endTime 
     INTO 
      #Residence2 
     FROM 
      #ShiftEmployees a 
      RIGHT OUTER JOIN #ResidenceOvertime b 
       ON a.dayDate = b.dayDate 
      INNER JOIN ShiftDetails c 
       ON c.shiftId = a.shiftId AND 
       c.shiftTypeId = b.shiftTypeId; 

      SET @is_trans = 0; 
    END ELSE BEGIN 
     RETURN; 
    END 
END; 

IF @is_trans = 1 BEGIN 
    WITH CTE_Residence_Overtime_trans AS (
     SELECT * FROM #Residence1 
    ) 

    UPDATE t1 
    SET 
     t1.over_time = t1.over_time 
      + CAST(RIGHT('0'+ CAST(overtimeHours as varchar(2)),2) 
      +':00:00' As Time) 
      + CAST(RIGHT('0'+ CAST(@total_min as varchar(2)),2) 
      +':00:00' As Time), 
     t1.day_flag = t1.day_flag + 'R1', 
     t1.day_desc = 'R::' 
      + CTE_Residence_Overtime_trans.shiftName +'[ ' 
      + CTE_Residence_Overtime_trans.name +' ]' 
    FROM 
     rr_overtime AS t1 
     INNER JOIN CTE_Residence_Overtime_trans 
      ON t1.[trans_date] = CTE_Residence_Overtime_trans.[dayDate] 
    WHERE 
     t1.emp_num = @empNum; 

    UPDATE rr_overtime 
    SET 
     over_time = CAST(RIGHT('0'+ CAST(0 as varchar(2)),2)+':00:00' As Time), 
     day_flag = day_flag +'R2' 
    WHERE 
     trans_date = @TomorrowDate AND 
     emp_num = @empNum; 

END ELSE BEGIN 
    WITH CTE_Residence_Overtime AS (
     SELECT * FROM #Residence2 
    ) 

    UPDATE t1 
    SET 
     t1.over_time = CAST(RIGHT('0'+ CAST(overtimeHours as varchar(2)), 2) 
      +':00:00' As Time) 
     + CAST(RIGHT('0'+ CAST(@total_min as varchar(2)),2)+':00:00' As Time), 
     t1.day_flag = t1.day_flag + 'R1', 
     t1.day_desc = 'R::' 
      + CTE_Residence_Overtime.shiftName +'[ ' 
      + CTE_Residence_Overtime.name +' ]' 
    FROM 
     rr_overtime AS t1 
     INNER JOIN CTE_Residence_Overtime 
      ON t1.[trans_date] = CTE_Residence_Overtime.[dayDate] 
    WHERE 
     t1.emp_num = @empNum ; 

    UPDATE rr_overtime 
    SET 
     over_time = CAST(RIGHT('0'+ CAST(0 as varchar(2)),2)+':00:00' As Time), 
     day_flag = day_flag +'R2' 
    WHERE 
     trans_date = @TomorrowDate AND 
     emp_num = @empNum; 

END 
+0

Quali duplicazioni stai ottenendo? –

+0

@TabAlleman: sto parlando di duplicazione nel codice non nei dati. –

+0

@just_name Va bene se si utilizzano alcune funzioni per evitare il calcolo duplicato – thangchung

risposta

2

Si potrebbe provare quanto segue per evitare la duplicazione. Fondamentalmente crea la tua tabella temporanea prima (ho indovinato i tipi di dati), quindi usa solo questa tabella per l'inserto dal momento che stai usando se sarà l'uno o l'altro che si inserisce in questo.

Quindi non hai bisogno di CTE se stai facendo Seleziona * dal tavolo quindi chiama direttamente dal tavolo. Poiché la tabella avrà solo i dati da un selezionare o l'altro e i nomi dei campi sono gli stessi ecc possiamo semplicemente usare un aggiornamento per questo e non più necessari se è:

Create table #Residence (dayDate varchar(9), shiftName varchar(20), limit int, startTimeBefore time, endTimeBefore time, dayAdd int, name varchar(30), overtimeHours int, startTime time, endTime time) 

IF @transExist > 0 

     BEGIN 

     IF @transType = 1 --INSERT 
      BEGIN 
      Insert into #Residence 
      SELECT a.dayDate,a.shiftName,a.limit,b.startTimeBefore,b.endTimeBefore,b.dayAdd,b.name,b.overtimeHours,c.startTime,c.endTime 
      FROM #ShiftTrans a RIGHT OUTER JOIN #ResidenceOvertime b 
      ON a.dayDate = b.dayDate 
      INNER JOIN ShiftDetails c 
      ON c.shiftId = a.shiftId AND c.shiftTypeId = b.shiftTypeId; 
      END 
     ELSE 
      BEGIN 
      RETURN ; 
      END 
     END 

    ELSE 
    BEGIN 

     IF @employeeExist > 0 
      BEGIN 
      Insert into #Residence 
      SELECT a.dayDate,a.shiftName,a.limit,b.startTimeBefore,b.endTimeBefore,b.dayAdd,b.name,b.overtimeHours,c.startTime,c.endTime 
      FROM #ShiftEmployees a RIGHT OUTER JOIN #ResidenceOvertime b 
      ON a.dayDate = b.dayDate 
      INNER JOIN ShiftDetails c 
      ON c.shiftId = a.shiftId AND c.shiftTypeId = b.shiftTypeId; 
      END 
     ELSE 
      BEGIN 
      RETURN ; 
      END 
    END; 

    UPDATE t1 
    SET t1.over_time = t1.over_time + CAST(RIGHT('0'+ CAST(overtimeHours as varchar(2)), 2)+':00:00' As Time) + 
    CAST(RIGHT('0'+ CAST(@total_min as varchar(2)), 2)+':00:00' As Time), 
    t1.day_flag = t1.day_flag + 'R1', 
    t1.day_desc = 'R::' +R.shiftName +'[ '+ R.name +' ]' 

    FROM rr_overtime AS t1 
    INNER JOIN #Residence R 
    ON t1.[trans_date] = R.[dayDate] 
    WHERE t1.emp_num = @empNum ; 

    UPDATE rr_overtime SET over_time = CAST(RIGHT('0'+ CAST(0 as varchar(2)), 2)+':00:00' As Time), 
    day_flag = day_flag +'R2' 
    WHERE trans_date = @TomorrowDate AND emp_num = @empNum; 
+0

Suggerimento: si deve sempre usare 'SELECT ... INTO #blah FROM tab1, tab2, WHERE 1 = 2' per creare le tabelle temporanee, in questo modo hai sempre i giusti tipi di dati e non subisci mai problemi di collazione. L'unico lato negativo è quando vuoi renderli NULL-capable quando non lo sono e/o quando c'è un campo IDENTITY(); ma quelli che puoi aggirare aggiungendo semplicemente 0. – deroby

3

Il codice crea la tabella temporanea sembra identico, quindi l'ho fuso nel CTE. Il codice nell'aggiornamento presenta differenze minori che possono essere gestite con la dichiarazione CASE. L'istruzione CASE può essere spostata nello CTE se necessario.

Quindi dare una prova:

IF @transExist > 0 
BEGIN 
    IF @transType <> 1 RETURN ELSE SET @is_trans = 1 
END 
ELSE 
BEGIN 
    IF @employeeExist <= 0 RETURN ELSE SET @is_trans = 0 
END 

;WITH CTE_Residence_Overtime_trans 
AS 
(
     SELECT a.dayDate,a.shiftName,a.limit,b.startTimeBefore,b.endTimeBefore,b.dayAdd,b.name,b.overtimeHours,c.startTime,c.endTime 
     FROM #ShiftTrans a RIGHT OUTER JOIN #ResidenceOvertime b 
     ON a.dayDate = b.dayDate 
     INNER JOIN ShiftDetails c 
     ON c.shiftId = a.shiftId AND c.shiftTypeId = b.shiftTypeId; 
) 

UPDATE t1 
SET t1.over_time = 
    CASE 
    WHEN @Is_Trans = 1 THEN 
     t1.over_time + CAST(RIGHT('0'+ CAST(overtimeHours as varchar(2)), 2)+':00:00' As Time) + 
     CAST(RIGHT('0'+ CAST(@total_min as varchar(2)), 2)+':00:00' As Time) 
    ELSE 
     CAST(RIGHT('0'+ CAST(overtimeHours as varchar(2)), 2)+':00:00' As Time) + 
     CAST(RIGHT('0'+ CAST(@total_min as varchar(2)), 2)+':00:00' As Time) 
    END, 
    t1.day_flag = t1.day_flag + 'R1', 
    t1.day_desc = 'R::' +CTE_Residence_Overtime_trans.shiftName +'[ '+ CTE_Residence_Overtime_trans.name +' ]' 
FROM rr_overtime AS t1 
INNER JOIN CTE_Residence_Overtime_trans 
ON t1.[trans_date] = CTE_Residence_Overtime_trans.[dayDate] 
WHERE t1.emp_num = @empNum ; 

UPDATE rr_overtime SET over_time = CAST(RIGHT('0'+ CAST(0 as varchar(2)), 2)+':00:00' As Time), 
day_flag = day_flag +'R2' 
WHERE trans_date = @TomorrowDate AND emp_num = @empNum; 
5

Guardando il codice, sembra che questo dovrebbe funzionare:

WITH CTE_Residence_Overtime_trans AS (
    SELECT 
     a.dayDate, 
     a.shiftName, 
     a.limit, 
     b.startTimeBefore, 
     b.endTimeBefore, 
     b.dayAdd, 
     b.name, 
     b.overtimeHours, 
     c.startTime, 
     c.endTime 
    FROM 
     ( 
      select dayDate, shiftName, limit 
      from #ShiftTrans 
      where (@transExist > 0 and @transType = 1) 
     union all 
      select dayDate, shiftName, limit 
      from #ShiftEmployees 
      where (not (@transExist>0 and @transType=1)) and @employeeExist>0 
     ) a 
    JOIN #ResidenceOvertime b 
     ON a.dayDate = b.dayDate 
    JOIN ShiftDetails c 
     ON c.shiftId = a.shiftId AND 
     c.shiftTypeId = b.shiftTypeId 
) 

UPDATE t1 
SET 
    t1.over_time = t1.over_time 
     + CAST(CAST(overtimeHours as varchar(2))+':00:00' As Time) 
     + CAST(CAST(@total_min as varchar(2))+':00:00' As Time), 
    t1.day_flag = t1.day_flag + 'R1', 
    t1.day_desc = 'R::' + CTE.shiftName +'[ ' + CTE.name +' ]' 
FROM 
    rr_overtime AS t1 
    INNER JOIN CTE_Residence_Overtime_trans CTE 
     ON t1.[trans_date] = CTE.[dayDate] 
WHERE 
    t1.emp_num = @empNum; 

UPDATE rr_overtime 
SET 
    over_time = CAST('00:00:00' As Time), 
    day_flag = day_flag +'R2' 
WHERE 
    trans_date = @TomorrowDate AND 
    emp_num = @empNum; 

Questo rende un'unione tutto selezionare sia della temperatura. tabelle, ma recupera solo i dati da quello corretto in base alle variabili e li utilizza come CTE per l'aggiornamento. Ho rimosso anche il join esterno perché il tavolo era anche coinvolto in un join interno.

Anche se questo può ridurre il codice, non è sempre il modo migliore di fare le cose, perché potrebbe causare l'uso di un piano di query più complesso che causa problemi di prestazioni.

Ho rimosso anche le funzioni di destra (2, ...) dalla conversione dell'ora, poiché la conversione dell'ora funziona anche senza zero iniziale e l'ultima è stata fissata solo 00:00:00.

+0

Dovresti anche aggiungere il controllo per le variabili prima di uscire completamente se non è necessario alcun aggiornamento, non includerlo a questo. –

2

tenta di utilizzare query dinamica

In query di inserimento solo la tabella è da varia dipende dalle condizioni, giusto? usa qualcosa di simile

DECLARE @FromTable NVARCHAR(250) 
IF @transExist > 0 BEGIN 
IF @transType = 1 BEGIN --INSERT 
    SELECT @FromTable = '#ShiftTrans' 
    SET @is_trans = 1; 
END ELSE BEGIN 
    RETURN ; 
END 
END ELSE BEGIN 
IF @employeeExist > 0 BEGIN 

     SELECT @FromTable = '#ShiftEmployees' 
     SET @is_trans = 0; 
END ELSE BEGIN 
    RETURN; 
END 
END; 

DECLARE @DynamicQuery NVARCHAR(MAX) = 'SELECT 
     a.dayDate, 
     a.shiftName, 
     a.limit, 
     b.startTimeBefore, 
     b.endTimeBefore, 
     b.dayAdd, 
     b.name, 
     b.overtimeHours, 
     c.startTime, 
     c.endTime 
    INTO 
     #Residence1 
    FROM 
     '[email protected]+' a 
     RIGHT OUTER JOIN #ResidenceOvertime b 
      ON a.dayDate = b.dayDate 
     INNER JOIN ShiftDetails c 
      ON c.shiftId = a.shiftId AND 
      c.shiftTypeId = b.shiftTypeId' 


EXECUTE (@DynamicQuery) 

modo SAMe creare query dinamica per la parte aggiornamento anche ...

Thejus T V

2

prima parte combina le #Trans e #Employee usando UNION ALL. Ma dal momento che avete ancora a differenziare i due al fine di fare

t1.over_time = 
    t1.over_time --<------------- One is cumalative add and the other isn't 
    + CAST(RIGHT('0'+ CAST(overtimeHours as varchar(2)),2) 
     +':00:00' As Time) 
    + CAST(RIGHT('0'+ CAST(@total_min as varchar(2)),2) 
     +':00:00' As Time), 

per Trans e

t1.over_time = 
    CAST(RIGHT('0'+ CAST(overtimeHours as varchar(2)), 2) 
     +':00:00' As Time) 
    + CAST(RIGHT('0'+ CAST(@total_min as varchar(2)),2) 
     +':00:00' As Time), 

per i dipendenti, sto aggiungendo colonna EmployeeType nel CTE. Inoltre, ho fatto alcune ipotesi sul tipo di dati di destinazione nella tabella rr_datatype. Se questo è, in realtà, TIME o DATETIME o qualche altra variante, si dovrebbe invece utilizzare la funzione DATEADD.MSDN page here ..

E, infine, il secondo UPDATE dichiarazione può anche essere combinato nella prima se si sta solo con l'intenzione di aggiornare i record coinvolti nella prima UPDATE e non cercando di aggiornare l'intera tabella.

; WITH TransAndEmployee AS (
    SELECT 'T' AS EmployeeType, dayDate, shiftName, limit 
    FROM #ShiftTrans 
    UNION ALL 
    SELECT 'E' AS EmployeeType, dayDate, shiftName, limit 
    FROM #ShiftEmployees 
), PoundOvertime AS (
    SELECT * 
    FROM TransAndEmployee a 
    RIGHT OUTER JOIN #ResidenceOvertime b 
     ON a.dayDate = b.dayDate 
    INNER JOIN ShiftDetails c 
     ON c.shiftId = a.shiftId 
     AND c.shiftTypeId = b.shiftTypeId; 
) 
UPDATE ot 
SET over_time = DATEADD(mi,@total_min, 
        DATEADD(hh,overtimeHours,CASE WHEN EmployeeType = 'T' THEN over_time ELSE '0:00' END) 
       ), 
    day_flag = day_flag + 'R1', 
    day_desc = 'R::' + CTE_Residence_Overtime_trans.shiftName + '[ ' + CTE_Residence_Overtime_trans.name + ' ]' 
FROM rr_overtime ot 
INNER JOIN PoundOvertime p 
    ON ot.[trans_date] = p.[dayDate] 
WHERE ot.emp_num = @empNum 


UPDATE rr_overtime 
SET 
    over_time = CAST('00:00:00' As Time), -- You can probably do over_time = '00:00' if over_time is TIME 
    day_flag = day_flag +'R2' 
WHERE 
    trans_date = @TomorrowDate AND 
    emp_num = @empNum; 

Un'altra ipotesi che ho fatto ... sotto sembrava un po 'strano per me. Immaginavo che stavi cercando di aggiungere "minuti" ... tuttavia questa stringa sembra essere stata aggiunta a ore. L'ho "corretto" ... fammi sapere se era una cattiva ipotesi.

+ CAST(RIGHT('0'+ CAST(@total_min as varchar(2)),2) 
    +':00:00' As Time),