2009-09-06 7 views
0

Utilisation de SQL Server 2000Comment écrire une requête de calcul en SQL?

Ma requête.

SELECT 
    (Format(IIf(CLng(OutTime) > 180000, CDate('18:00:00'), CDate(Format(OutTime, '00:00:00'))) - IIf(CLng(InTime) < 90000, CDate('09:00:00'), CDate(Format(InTime, '00:00:00'))), 'hh:nn:ss')) As WorkTime, 
    (Format(IIf(CLng(InTime) < 90000, CDate('09:00:00') - CDate(Format(InTime, '00:00:00')), 0) + IIf(CLng(OutTime) > 180000, CDate(Format(OutTime, '00:00:00')) - CDate('18:00:00'), 0), 'hh:nn:ss')) As OverTime 
FROM table 

La requête ci-dessus est une requête d'accès, je veux écrire une même requête en SQL.

Condition.

Je veux calculer le temps après 090000 (HH: MM: SS) avant 180000 vient en travail, avant 090000 après 180000 vient en heures supplémentaires.

INTIME, type de données Outime est varchar dans la base de données

Am nouveau à SQL Server 2000

Comment écrire une requête SQL de ce qui précède même?

+3

1. Ce * est * SQL. SQL Server et Access utilisent tous deux SQL. 2. Veuillez reformater sur plusieurs lignes pour plus de lisibilité si vous voulez encourager les gens à répondre. –

+0

En quoi cette requête ne fonctionne-t-elle pas pour vous? – Unsliced

+0

N'accepte pas CLng, CDate. – Gopal

Répondre

0

Voici traduit littéralement requête TSQL 2000. Bien que , il pourrait être réécrite pour une meilleure performance:

Select Convert(char(8), 
      case when DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime)>'18:00:00' 
       Then Cast('18:00:00' as datetime) 
       Else DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime) 
      End 
      - 
      Case when DateAdd(Day,-DateDiff(Day, 0, InTime), InTime) <'09:00:00' 
       Then Cast('09:00:00' as datetime) 
       Else DateAdd(Day,-DateDiff(Day, 0, InTime), InTime) 
      End, 
      8 
     ) as WorkTime, 
    Convert(char(8), 
      Case when DateAdd(Day,-DateDiff(Day, 0, InTime), InTime) <'09:00:00' 
       Then Cast('09:00:00' as datetime) - 
        DateAdd(Day,-DateDiff(Day, 0, InTime), InTime) 
       Else Cast('00:00:00' as datetime) 
      End 
      + 
      case when DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime)>'18:00:00' 
       Then DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime) - 
        Cast('18:00:00' as datetime) 
       Else Cast('00:00:00' as datetime) 
      End, 
      8 
     ) as OverTime 
From Table 

Ajouté plus tard:

Si InTime et OutTime temps partiel ont uniquement (la partie Date est le 1er janvier 1900), vous pouvez utiliser directement InTime et OutTime. Sinon, vous devez extraire une partie du temps de la colonne datetime, comme:

DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime) 

(c'est le meilleur moyen d'obtenir une partie du temps seulement)

Au lieu de:

DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime)>'18:00:00' 

Vous pouvez utiliser

Datepart(hh,OutTime)>17 

PScomme votre temps est stocké sous forme de chaîne, vous n'avez pas besoin d'avoir une partie temps seulement. Vous pouvez les jeter à datetime, ou vous pouvez aussi écrire

cast(left(inTime,2) as int) < 9 
+0

@Niikola - Affichage d'une erreur dans l'erreur de dépassement Arithmetic Express, Conversion du type de données Expression en datetime – Gopal

+0

Quel type de données sont vos colonnes InTime et OutTime? – Niikola

+0

et contiennent-ils aussi une partie date, ou juste une partie temps? – Niikola

0

Je ne pense pas qu'il y ait un moyen très facile et simple à faire - notamment en raison de stocker des valeurs de temps dans VARCHAR - ce qui est vraiment fait ce difficile .....

Quoi qu'il en soit, j'ai utilisé une approche avec deux fonctions - une dbo.GetSeconds qui convertit une représentation sous forme de chaîne d'une valeur temporelle ('103500' -> 10:35:00 heures) en un nombre de secondes, puis une seconde dbo.GetOvertime qui détecte si est le temps supplémentaire.

CREATE FUNCTION dbo.GetSeconds(@input varchar(20)) 
RETURNS int 
AS BEGIN 
    DECLARE @Hour INT 
    DECLARE @Minute INT 
    DECLARE @Second INT 

    DECLARE @TotalSeconds INT 

    SET @Hour = CAST(SUBSTRING(@input, 0, LEN(@input)-3) AS INT) 
    SET @Minute = CAST(LEFT(RIGHT(@input, 4), 2) AS INT) 
    SET @Second = CAST(RIGHT(@input, 2) AS INT) 

    SET @TotalSeconds = @Hour * 3600 + @Minute * 60 + @Second 

    RETURN @TotalSeconds 
END 


CREATE FUNCTION dbo.GetOvertime(@fromSeconds INT, @toSeconds INT) 
RETURNS int 
AS BEGIN 
    DECLARE @Overtime INT 

    SET @Overtime = 0 

    IF @fromSeconds < 32400 -- 32400 seconds = 09:00 hours 
    SET @Overtime = @OverTime + (32400 - @fromSeconds) 

    IF @toSeconds > 64800 -- 64800 seconds = 18:00 hours 
    SET @Overtime = @OverTime + (@toSeconds - 64800) 

    RETURN @Overtime 
END 

Avec ces deux fonctions en place, je peux calculer assez facilement ce que vous cherchez:

SELECT 
    dbo.GetOvertime(dbo.GetSeconds(InTime), dbo.GetSeconds(OutTime)) 'Overtime', 
    (dbo.GetSeconds(OutTime) - dbo.GetSeconds(InTime) - 
    dbo.GetOvertime(dbo.GetSeconds(InTime), dbo.GetSeconds(OutTime))) 'Worktime', 
FROM YourTable 

Il est un peu impliqué - comme je l'ai dit, si vous seriez sur SQL Server 2008 et en utilisant le type de données TIME, les choses seraient beaucoup plus faciles!

Marc

+0

Heavy, car vous travaillez avec des cordes. Au lieu des opérations Streing vous pouvez utiliser: SET @Hour = DatePart (hh, @ entrée) SET @Minute = DatePart (mi, @ entrée) SET @Second = DatePart (ss, @ entrée) Bien que, à côté DATEIFF (ss, 0, DateAdd (Jour, -DateDiff (Jour, 0, @input), @input)) À la fin, la dernière requête ne suit pas la logique d'origine – Niikola

+0

Désolé pour unformatted commentaire. Comment ajouter un saut de ligne dans les commentaires? – Niikola

+0

Étant donné que les données semblent avoir le format «90000» pour 09:00:00, cette approche avec DATEPART ne fonctionnera pas: Msg 241, Niveau 16, État 1, Ligne 9 La conversion a échoué lors de la conversion de la date et/ou heure de la chaîne de caractères. –

0

Vous pouvez utiliser et dateadd substring pour convertir le « 090000 » à un vrai champ datetime. Ensuite, vous pouvez utiliser CASE et DATEDIFF pour séparer le travail et les heures supplémentaires. Le formatage final peut être effectué avec CONVERT. Voici un exemple:

select 
    case when outtime-intime > '9:00:00' then '09:00:00' 
    else convert(varchar(30), outtime-intime, 108) 
    end as WorkTime, 
    case when outtime-intime <= '9:00:00' then '00:00:00' 
    else convert(varchar(30), outtime-intime-'9:00:00', 108) 
    end as OverTime 
from (
    select 
    dateadd(hh,cast(substring('090000',1,2) as int),0) + 
    dateadd(mi,cast(substring('090000',3,2) as int),0) + 
    dateadd(ss,cast(substring('090000',5,2) as int),0) as InTime, 
    dateadd(hh,cast(substring('180500',1,2) as int),0) + 
    dateadd(mi,cast(substring('180500',3,2) as int),0) + 
    dateadd(ss,cast(substring('180500',5,2) as int),0) as OutTime 
) vw 

Ce imprimera:

09:00:00 00:05:00 
+0

Il ne suit pas la logique demandée. Il fonctionne avec des heures seulement et dans le cas d'une heure de retard dans et une heure de retard, il affichera 9 heures WorkTime et 0 OverTime, tandis que l'original affichera 8 heures WT et 1 heure OT – Niikola

+0

Que voulez-vous dire, fonctionne avec des heures seulement? L'exemple est en fait en quelques minutes. Et la question compte les 9 premières heures comme temps de travail, pas seulement les 8 premières (il doit travailler dans Elbonia) – Andomar

+0

Je veux dire, cela a fonctionné avec des heures seulement avant que vous éditiez votre message: p Cette partie du code est extrêmement inefficace : dateadd (hh, cast (sous-chaîne ('090000', 1,2) comme int), 0) + dateadd (mi, cast (sous-chaîne ('090000', 3,2) comme int), 0) + dateadd (ss, cAST (substring ('090000', 5,2) int), 0) vous pouvez utiliser cast ('09: 00' comme datetime) – Niikola

0

Voici le code pour le serveur SQL 2000. 2005+ pourrait le faire sans sous-requête en utilisant jointure croisée.

Select DateAdd(mi, (Case When bef<0 Then bef else 0 end + Case When aft<0 Then aft else 0 end), diff) as WorkTome, 
     DateAdd(mi, (Case When bef>0 Then bef else 0 end + Case When aft>0 Then aft else 0 end), 0) as OverTime 
From (  
Select outTime-inTime as diff, 
     DateDiff(mi,t.inTime,'09:00') as bef, 
     DateDiff(mi,'18:00',t.outTime) as aft 
    From Table t) as a 

Si votre inTime et colonnes outTime partie date de hase aussi, la requête est légèrement différente:

Select DateAdd(mi, (Case When bef<0 Then bef else 0 end + Case When aft<0 Then aft else 0 end), diff) as WorkTome, 
     DateAdd(mi, (Case When bef>0 Then bef else 0 end + Case When aft>0 Then aft else 0 end), 0) as OverTime 
From (  
Select outTime-inTime as diff, 
     DateDiff(mi, DateAdd(Day,-DateDiff(Day, 0, t.inTime), t.inTime),'09:00') as bef, 
     DateDiff(mi,'18:00',DateAdd(Day,-DateDiff(Day, 0, t.OutTime), t.OutTime)) as aft 
    From #t t) as a 
+0

vous obtiendrez le résultat en datetime. Si vous voulez l'obtenir sous forme de chaîne, ajoutez simplement Convert (char (5), , 8) pour 'HH: mm' – Niikola

+0

Tout ce que je reçois est: Msg 8117, Niveau 16, État 1, Ligne 4 Opérande Le type de données varchar n'est pas valide pour l'opérateur de soustraction. –

+0

Le point est: les données source "InTime" et "OutTime" est * NOT * au format DATETIME - c'est une chaîne VARCHAR, comme l'OP mentionné –

0

I Missed type de inTime et outTime. Voici la version pour varchar

Manqué, mais vous avez juste à faire Cast (inTime comme datetime). Utilisez la première des 2 requêtes précédentes:

Select DateAdd(mi, (Case When bef<0 Then bef else 0 end + Case When aft<0 Then aft else 0 end), diff) as WorkTome, 
     DateAdd(mi, (Case When bef>0 Then bef else 0 end + Case When aft>0 Then aft else 0 end), 0) as OverTime 
    From (  
    Select Cast(t.outTime as datetime)-Cast(t.inTime as datetime) as diff, 
     DateDiff(mi,Cast(t.outTime as datetime),'09:00') as bef, 
     DateDiff(mi,'18:00',Cast(t.outTime as datetime)) as aft 
    From Table t) as a 
Questions connexes