2017-05-03 1 views
2

Je sais que count (*) - renvoie le nombre total de toutes les lignes, y compris les valeurs null. count (colName) - renvoie le nombre total de toutes les lignes dans lesquelles colName n'est pas nul.Pourquoi il existe une différence de comportement de compte SQL (*) vs compte SQL (numérique)

Aujourd'hui, un de mes collègues a eu un problème avec count() dans SQL. Il essayait d'obtenir le nombre de lignes d'une vue après avoir appliqué un filtre de date.

Voir Retour Structure de données

[Year]     VARCHAR(4)   
,[Month]    VARCHAR(4)   
,AType     VARCHAR(20)  
,PActualsID    INT    
,EID     VARCHAR(12)  
,CID     INT    
,CGId     INT    
,EMargin    NUMERIC(17,3)  
,Period     DATETIME   
,PLID     INT    
,PCID     INT    
,PSID     INT    
,VPID     INT    
,VSID     INT    
,STID     INT    

Query 1

SELECT * from vw_ActualAllocation_New 
where EntityId = '442105'  and 
     Period >= '01-Jan-2017' AND Period < '01-Jan-2018' 

Cela renvoie environ 94 dossiers.

Recherche 2

SELECT Count(*) from vw_ActualAllocation_New 
where EID = '442105' and 
     Period >= '01-Jan-2017' AND Period < '01-Jan-2018' 

Cela renvoie une erreur

Msg 241, niveau 16, état 1, ligne 1 Échec de la conversion la date et/ou le temps de chaîne de caractères.

Interrogation 3

SELECT Count(EMargin) from vw_ActualAllocation_New 
where EID = '442105' and 
     Period >= '01-Jan-2017' AND Period < '01-Jan-2018' 

Cela me retourne compte que 94.

S'il vous plaît noter que EMARGIN est un type de données NUMERIC et tous les autres types tels que les retours int et VARCHAR même erreur.

Veuillez partager vos réflexions sur la différence entre ces deux comportements.

environnement SQL Server: Microsoft SQL Server 2012 (Build 7601: Service Pack 1) (Hypervisor)

MISE À JOUR - Afficher le code

CREATE VIEW [dbo].[vw_ActualAllocation_New] 
SELECT D.Year, D.Month, A.AType, A.PAID, D.EntityID, D.CustomerID 
,B.CGId, SUM(A.EBITRMargin) AS EBITRMargin 
,CONVERT(DATETIME,D.Month + '-01-' + D.Year) AS Period, D.PLID, D.PCID 
,D.PSID, D.VPID, D.VSID,D.STID 
FROM dbo.AAllocations AS A 
INNER JOIN dbo.PActuals AS D ON D.PActualsID = A.PActualsID AND D.Active = 1 
INNER JOIN dbo.Customer AS B ON D.CustomerID = B.CustomerID AND D.EntityID = 
B.EntityID 
INNER JOIN dbo.AStatus AS C ON A.ASID = C.ASID 
WHERE (A.Active = 1) AND (C.Active = 1) AND (C.Reference = 'Actuals') AND 
(C.Status = 1) 
GROUP BY D.Year, D.Month, A.AType, A.PAID, D.EntityID, D.CustomerID, B.CGId, 
D.PLID, D.PCID, D.PSID, D.VPID, D.VSID, D.STID 

Mise à jour Conclusion

Atteint une conclusion comme suggéré par Gordon, et si vous estimez que vous pouvez avoir une autre idée, s'il vous plaît le poster ici J'ai aussi essayé avec les données de la vue, dans une nouvelle table et son fonctionnement bien. Un problème se produit lors de l'accès directement à partir de la vue. La génération de vue se fait avec beaucoup de données et impossible de l'afficher ici en raison de sa taille énorme et des accords de confidentialité.Merci de votre compréhension mes limites et me aider

+0

Quel est le type de données de Period? Vous devriez vraiment utiliser des chaînes de date conformes ANSI. –

+1

l'erreur n'a rien à voir avec ce que vous incluez dans 'count'. la comparaison de date échoue comme le message d'erreur le suggère. –

+0

Je suis un peu d'accord avec vkp mais il ne devrait pas échouer si c'est la même requête ci-dessous. Intrigué honnêtement. – SS97

Répondre

1

La cause la plus probable du problème est cette ligne de code:

CONVERT(DATETIME, D.Month + '-01-' + D.Year) AS Period 

Dans SQL Server, vous ne devez jamais utiliser CONVERT() d'une chaîne à une date sans préciser le format ou l'utilisation de formats standards (YYYYMMDD est préféré par SQL Server mais je considère que YYYY-MM-DD est aussi acceptable).

Dans les anciennes versions de SQL Server, vous pouvez le faire:

CONVERT(DATE, d.Year + RIGHT('00' + D.Month, 2) + '01') as period 

Cette conversion sera toujours travailler. Dans les versions plus récentes, utilisez datefromparts():

DATEFROMPARTS(d.Year, d.Month, 1) as Period 

Pourquoi est-ce qui se passe? Je spécule que le format de date est interprété comme JJ-MM-AAAA au lieu de MM-JJ-AAAA. En d'autres termes, ce que vous pensez est le 1er février, c'est vraiment le 2 janvier.

En outre, les valeurs de période pour l'entité '442105' sont toutes converties en une date raisonnable. La clause WHERE filtre les mauvaises valeurs. Le problème est avec d'autres entités et le problème, comme Damien souligne est où les valeurs sont évaluées dans le moteur d'exécution.

+0

Je reçois des valeurs tout en sélectionnant * from view, mais en obtenant l'erreur lors de l'application count (*) 'Impossible de construire la date du type de données, certains arguments ont des valeurs qui ne sont pas valides.' – kbvishnu

+0

Plus tôt la période était datetime, maintenant elle était rendez-vous amoureux. – kbvishnu

+0

J'essayais comme ceci 'SELECT count (*) de vw_ActualAllocation_New_Edit WHERE EntityId = '442105' et Période> = '2017-01-01' ET Période <'2018-01-01'' – kbvishnu