Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Obtenha o primeiro dia da semana no SQL Server


Para responder por que você está recebendo uma segunda-feira e não um domingo:

Você está adicionando um número de semanas à data 0. O que é a data 0? 1900-01-01. Qual foi o dia em 1900-01-01? Segunda-feira. Então, em seu código, você está dizendo quantas semanas se passaram desde segunda-feira, 1º de janeiro de 1900? Vamos chamar isso de [n]. Ok, agora adicione [n] semanas a segunda-feira, 1º de janeiro de 1900. Você não deve se surpreender que isso acabe sendo uma segunda-feira. DATEADD não tem ideia de que você deseja adicionar semanas, mas apenas até chegar a um domingo, é apenas adicionar 7 dias, depois adicionar mais 7 dias, ... assim como DATEDIFF só reconhece os limites que foram cruzados. Por exemplo, ambos retornam 1, embora algumas pessoas reclamem que deve haver alguma lógica sensata incorporada para arredondar para cima ou para baixo:
SELECT DATEDIFF(YEAR, '2010-01-01', '2011-12-31');
SELECT DATEDIFF(YEAR, '2010-12-31', '2011-01-01');

Para responder como conseguir um domingo:

Se você quiser um domingo, escolha uma data base que não seja uma segunda-feira, mas sim um domingo. Por exemplo:
DECLARE @dt DATE = '1905-01-01';
SELECT [start_of_week] = DATEADD(WEEK, DATEDIFF(WEEK, @dt, CURRENT_TIMESTAMP), @dt);

Isso não será interrompido se você alterar seu DATEFIRST configuração (ou seu código está sendo executado para um usuário com uma configuração diferente) - desde que você ainda queira um domingo, independentemente da configuração atual. Se você quiser que essas duas respostas sejam jive, então você deve usar uma função que faça dependem do DATEFIRST configuração, por exemplo
SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP);

Portanto, se você alterar seu DATEFIRST configuração para segunda-feira, terça-feira, o que você tem, o comportamento vai mudar. Dependendo de qual comportamento você deseja, você pode usar uma destas funções:
CREATE FUNCTION dbo.StartOfWeek1 -- always a Sunday
(
    @d DATE
)
RETURNS DATE
AS
BEGIN
    RETURN (SELECT DATEADD(WEEK, DATEDIFF(WEEK, '19050101', @d), '19050101'));
END
GO

...ou...
CREATE FUNCTION dbo.StartOfWeek2 -- always the DATEFIRST weekday
(
    @d DATE
)
RETURNS DATE
AS
BEGIN
    RETURN (SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, @d), @d));
END
GO

Agora, você tem muitas alternativas, mas qual delas tem melhor desempenho? Eu ficaria surpreso se houvesse alguma diferença importante, mas coletei todas as respostas fornecidas até agora e as executei em dois conjuntos de testes - um barato e outro caro. Eu medi as estatísticas do cliente porque não vejo E/S ou memória desempenhando um papel no desempenho aqui (embora isso possa entrar em jogo dependendo de como a função é usada). Nos meus testes os resultados são:

Consulta de atribuição "barata":
Function - client processing time / wait time on server replies / total exec time
Gandarez     - 330/2029/2359 - 0:23.6
me datefirst - 329/2123/2452 - 0:24.5
me Sunday    - 357/2158/2515 - 0:25.2
trailmax     - 364/2160/2524 - 0:25.2
Curt         - 424/2202/2626 - 0:26.3

Consulta de atribuição "caro":
Function - client processing time / wait time on server replies / total exec time
Curt         - 1003/134158/135054 - 2:15
Gandarez     -  957/142919/143876 - 2:24
me Sunday    -  932/166817/165885 - 2:47
me datefirst -  939/171698/172637 - 2:53
trailmax     -  958/173174/174132 - 2:54

Posso transmitir os detalhes dos meus testes, se desejar - parando aqui, pois isso já está ficando bastante prolixo. Fiquei um pouco surpreso ao ver o Curt's sair como o mais rápido no topo, dado o número de cálculos e código embutido. Talvez eu faça alguns testes mais completos e escreva sobre isso... se vocês não tiverem nenhuma objeção a eu publicar suas funções em outro lugar.