2009-02-09 9 views
3

J'ai un champ varchar dans SQL Sever 2005 qui est le stockage d'une valeur de temps dans le format « hh: mm ». Ss.mmmm »moyenne une valeur de temps dans SQL Sever 2005

Ce que je veux vraiment faire est de prendre la moyenne en utilisant la fonction intégrée globale de ces valeurs temporelles Cependant, ceci:.

SELECT AVG(TimeField) FROM TableWithTimeValues 

ne fonctionne pas, car (bien sûr) SQL varchars ne moyenne Cependant, cette

SELECT AVG(CAST(TimeField as datetime)) FROM TableWithTimeValues 
.

ne fonctionne pas non plus. s Je peux dire, SQL ne sait pas comment convertir une valeur avec seulement l'heure et aucune date dans un champ datetime. J'ai essayé une grande variété de choses pour que SQL transforme ce champ en un datetime, mais jusqu'ici, pas de chance.

Quelqu'un peut-il suggérer un meilleur moyen?

Répondre

7

SQL Server peut convertir une partie de date-heure d'une chaîne de caractères en date-heure, mais dans votre exemple, vous avez une précision de 4 décimales. SQL Server 2005 reconnaît seulement 3 endroits. Par conséquent, vous devez tronquer le plus à droite caractère:

create table #TableWithTimeValues 
(
    TimeField varchar(13) not null 
) 

insert into #TableWithTimeValues 
select '04:00:00.0000' 
union all 
select '05:00:00.0000' 
union all 
select '06:00:00.0000' 

SELECT CAST(TimeField as datetime) FROM #TableWithTimeValues 
--Msg 241, Level 16, State 1, Line 1 
--Conversion failed when converting datetime from character string. 

SELECT CAST(LEFT(TimeField, 12) as datetime) FROM #TableWithTimeValues 
--Success! 

Cela vous permet de convertir des valeurs valides en DATETIME à partir du 1900-01-01. SQL Server calcule les dates en fonction de 1 jour = 1 (entier). Des portions de jours sont alors des parties de la valeur 1 (c'est-à-dire que midi est 0,5). Parce qu'une date n'a pas été spécifiée dans la conversion, SQL Server a attribué la valeur de 0 jours (1900-01-01), ce qui correspond à notre besoin de moyenne de la partie de temps.

Pour effectuer une opération AVG le DATETIME, vous devez d'abord convertir le paramètre DATETIME en valeur décimale, effectuer l'agrégation, puis effectuer un retour. Par exemple

SELECT CAST(AVG(CAST(CAST(LEFT(TimeField, 12) as datetime) AS FLOAT)) AS DATETIME) FROM #TableWithTimeValues 
--1900-01-01 05:00:00.000 

Si vous devez stocker ce avec une place décimale supplémentaire, vous pouvez convertir le DATETIME à un VARCHAR avec une partie de temps seulement et pad la chaîne de retour à 13 caractères:

SELECT CONVERT(VARCHAR, CAST(AVG(CAST(CAST(LEFT(TimeField, 12) as datetime) AS FLOAT)) AS DATETIME), 114) + '0' FROM #TableWithTimeValues 
+0

AHA! C'était mon problème - le nombre de places après la virgule. Merci, un million, Cadaeic. –

5

Essayez cette

AVG(CAST(CAST('1900-01-01 ' + TimeField AS DateTime) AS Float)) 

Vous devriez vraiment stocker ces données dans une colonne datetime de toute façon. Utilisez simplement une date cohérente pour cette partie (1/1/1900 est très commun). Ensuite, vous pouvez simplement appeler AVG() et ne vous inquiétez pas à ce sujet.

+0

Sur le sujet de la façon dont les données sont stockées - croyez-moi, si j'étais responsable qui est comment il être stocké. Comme il est, je dois juste faire face à la table telle qu'elle existe. –

0

Comment pensez-vous faire la moyenne sur datetime?

Je suppose que vous avez besoin de GROUP BY certaine période (heure?), Et afficher Count (*)?

+0

un datetime est juste un nombre binaire de 8 octets. AVG devrait gérer cela très bien tant que toutes les parties de date sont les mêmes. –

+0

Non. Vous obtenez "Opérande data type datetime n'est pas valide pour l'opérateur avg". Mais alors pourquoi pas AVG (CAST (YourStringAsDateTime AS INT))? – dmajkic

+0

.. cos 'vous obtenez seulement la partie moyennée. Je tiens à dire que lancer à FLOAT sera inacceptable pour les fractions perdues. Il vaudrait mieux utiliser NUMERIC() avec une plus grande précision. – dmajkic

0

SQL Le serveur stocke les données datetime sous la forme de 2 entiers sur 4 octets, d'où 8 à 8 octets. Le premier est le jour depuis la date de base et le second est en millisecondes depuis minuit.

Vous pouvez convertir une valeur de date-heure en nombre entier et effectuer des opérations mathématiques, mais la conversion ne renvoie que la partie "jours" de la valeur de date-heure, par ex. sélectionnez convert (int, getdate()). Il est plus difficile de retourner la partie "temps" en entier.

L'utilisation de SQL Server 2008 est-elle une option pour vous? Cette version a un nouveau dedicated time data type.

Merci, Andy.

0

Je définirais la différence entre toutes les dates et un point arbitraire (01/01/1900), le moyenniser et le rajouter ensuite au point arbitraire.

2

J'utilise la réponse de Cadaeic pour obtenir une réponse que je cherchais, donc je pensais que je devrais partager le code ....

Je cherchais une requête qui en moyenne tous mes temps ensemble et me donner un global Turn Around Time pour toutes les approbations. Voici une déclaration imbriquée qui vous donne l'AVG TAT pour son INDIVIDUELLES id et quand emboîtés un TAT global

SELECT 
-- calculates overall TAT for ALL Approvals for specified period of time 
-- depending on parameters of query 
CONVERT(VARCHAR, CAST(AVG(CAST(CAST(LEFT(Tat_mins, 12) as datetime) AS FLOAT)) AS DATETIME), 108) + '0' 

from 
(
-- tat is for individual approvals 
SELECT 
dbo.credit_application.decision_status, 
dbo.credit_application.application_id, 
cast(dbo.credit_application.data_entry_complete as date) as'Data Entry Date', 
cast(dbo.credit_application.decision_date as DATE) as 'Decision Date', 
avg(datediff(minute, dbo.credit_application.data_entry_complete, dbo.credit_application.decision_date)) as 'TAT Minutes', 
convert (char(5), DateAdd(minute, Datediff(minute,dbo.credit_application.data_entry_complete, dbo.credit_application.decision_date),'00:00:00'),108) as 'TAT_Mins' 
FROM dbo.credit_application 
where Decision_status not in ('P','N') 

group by dbo.credit_application.decision_status, 
dbo.credit_application.data_entry_complete, 
dbo.credit_application.decision_date 
--dbo.credit_application.application_id 
)bb 
Questions connexes