Problema com a consulta SQL Server usando ENTRE em onde com DATETIME
-
13-09-2019 - |
Pergunta
Eu tenho um procedimento armazenado que percorre os meses do ano fiscal e faz uma contagem para os itens de cada mês. Eu sei para um fato existem 176 itens, mas quando eu executar este ele retorna uma contagem total de 182. Eu tentei remover um segundo a partir @EndDate, mas então minha contagem total foi de 165. Então, eu estou tanto itens de contagem duas vezes, ou sem contar com todos eles. Alguém pode ajudar com o que estou fazendo de errado aqui? Abaixo está uma versão simplificada do que eu estou fazendo:
DECLARE @Date DATETIME
DECLARE @EndDate DATETIME
SELECT @Date = CAST((@Year - 1) as VARCHAR) + '-07-01'
SELECT @EndDate = DATEADD(Month, 1, @Date)
DECLARE @Count INT
SELECT @Count = 0
WHILE @Count < 12
BEGIN
SELECT
COUNT(yai.ID)
FROM
table_1 yai
INNER JOIN table_2 yat ON yai.ID = yat.ID
WHERE
(yat.Date_Received BETWEEN CONVERT(VARCHAR, @Date, 101) AND CONVERT(VARCHAR, @EndDate, 101)) AND
yai.Pro_Type = @Value AND yat.Type = 'PC'
SELECT @Count = @Count + 1
SELECT @Date = DATEADD(MONTH, 1, @Date)
SELECT @EndDate = DATEADD(MONTH, 1, @EndDate)
END
Solução
A partir do topo da minha cabeça.
SELECT DATEPART(month, yat.Date) as month, COUNT(yai.ID)
FROM table_1 yai
INNER JOIN table_2 yat ON yai.ID = yat.ID
WHERE
yai.Pro_Type = @Value AND yat.Type = 'PC'
AND DATEPART(year, yat.Date)=@Year
GROUP BY DATEPART(month, yat.Date)
ORDER BY DATEPART(month, yat.Date)
Outras dicas
O meio é inclusiva, para que o seu 1 segundo subtrair deveria estar lá (ou mesmo um dia). Meu palpite é que alguns Yais não têm yat correspondente.
Edit: O código é falsa. Você não pode fazer outra coisa senão a igualdade comparações com o formato 101.
Eu costumava dizer coisas engraçadas que eu sei para um fato que há 50 itens e sql retornou 60 ...
Eu descobri que estava sempre errado! :)
Tente descascar a partir da data e hora campos:
DATEADD (d, DATEDIFF (d, 0, GetDate ()), 0)
Você não poderia fazer isso em vez disso? A consulta a seguir lhe dará conta agrupadas por mês. Se você colocar isso em um ponto de vista, você pode então selecionar a partir da vista e usar uma cláusula WHERE para filtrar pelo ano e mês que você está interessado.
select year(yat.Date_Received) as year, month(yat.Date_Received) as month, count(*) as count
count(yai.ID)
from table_1 yai
inner join table_2 yat on yai.ID = yat.ID
where yai.Pro_Type = 'some_value'
and yat.Type = 'PC'
group by year(yat.Date_Received), month(yat.Date_Received)
Este é um caso clássico de um loop desnecessário é o código SQL, mas se você quiser resolver isso com um loop, mudar a sua escolha no loop de:
SELECT
COUNT(yai.ID)
para:
SELECT
@Date,@EndDate,*
e, em seguida, olhar para a saída e verificar as linhas retornadas
Por que não converter os meses do calendário em referências absolutas inteiros como este:
DECLARE @BeginDate datetime = '7/1/2008'
DECLARE @EndDate datetime = '6/30/2009'
--
-- Convert calendar months into an absoulte integer:
--
DECLARE @BeginMonth int = (DatePart(year, @BeginDate) * 12) + DatePart(month, @BeginDate)
DECLARE @EndMonth int = (DatePart(year, @EndDate) * 12) + DatePart(month, @EndDate)
SELECT COUNT(yai.ID)
FROM table_1 yai
INNER JOIN table_2 yat ON yai.ID = yat.ID
WHERE (DatePart(year, yat.Date_Received) * 12) + DatePart(month, yat.Date_Received)
BETWEEN @BeginMonth AND @EndMonth)
AND yai.Pro_Type = @Value
AND yat.Type = 'PC'
Eu encontrei esta pergunta, porque eu tinha problemas com o uso de Data de corda em consultas usando Entre e eu estava usando metadados , o meu colega de trabalho me ajudou, então eu espero que este ajuda-o demasiado:
N'convert(date,[fld_myDate]) Between convert(date,''01/01/2016'') AND convert(date,''08/26/2017'') '