Consulta avançada para pegar ultima dia do mês

Dúvidas, dicas e truques de PL/SQL. Aqui também vão assuntos relacionados a pacotes, triggers, funções, Java-Stored Procedures, etc
Responder
Jefries
Rank: Estagiário Sênior
Rank: Estagiário Sênior
Mensagens: 14
Registrado em: Dom, 09 Mai 2010 4:20 pm
Localização: Sorocaba

Boa tarde pessoal,

Estou tendo o seguinte problema, eu tenho este SELECT e preciso PEGAR O ultimo dia do mês para converter em number e fazer uma conta específica do meu sistema, eu passo o período desse jeito

'201008' --> ou seja preciso pegar o ultimo dia de agosto de 2008

o problema é que não posso usar o last_day para descobrir o ultimo dia do mês...

POr que? Por que esta consulta deverá funcionar em dois bancos
Oracle e SQL Server...


Já quebrei a cabeça em cima disso bastante tempo e até agora não consegui nenhuma solução....

Se alguém conhecer um jeito de fazer, e puder me ajudar, desde já eu agradeço.

Obrigado a todos.
Avatar do usuário
dr_gori
Moderador
Moderador
Mensagens: 5024
Registrado em: Seg, 03 Mai 2004 3:08 pm
Localização: Portland, OR USA
Contato:
Thomas F. G

Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered

Uma forma de fazer isso é:

Pega o PRIMEIRO dia do próximo mês e SUBTRAI 1.

Exemplo: AGOSTO de 2010...
Pra saber o primeiro dia do próxim mês é facil, pois sempre é dia 1 né. OU seja: 01 de SETEMBRO de 2010.

Pega essa data menos 1 terá o último dia de agosto!

:-o
Jefries
Rank: Estagiário Sênior
Rank: Estagiário Sênior
Mensagens: 14
Registrado em: Dom, 09 Mai 2010 4:20 pm
Localização: Sorocaba

Interessante cara...

mas assim, não entendi ainda isso muito bem...
você poderia me explicar melhor, se tiver tempo claro...

talvez me mandar um exemplo

lembrando que deve funcionar nos dois bancos

Desde de já valeu!
ballboas
Rank: Analista Júnior
Rank: Analista Júnior
Mensagens: 98
Registrado em: Qui, 02 Ago 2007 3:06 pm
Localização: sp
Érico Balboa

A pergunta mais cretina é aquela que não é feita

Cara, aparentemente esta função funciona, só tem q adequa-la para o SQL server, vê se te ajuda.

Selecionar tudo

create or replace
function ULTIMO_DIA(P_MESANO varchar2) return number is

vMES  number := TO_number(SUBSTR(P_MESANO,5,2));
vANO  number := TO_number(SUBSTR(P_MESANO,1,4));

vPAR_IMPAR number;
vUltDigAno number;

begin
  vPAR_IMPAR := MOD(SUBSTR(vANO,3,1),2);
  vUltDigAno := SUBSTR(vANO,4,1);
  
  if vMES in (1,3,5,7,8,10,12) then --Meses que têm 31 dias
    return 31;
  ELSIF VMES = 2 then               --Fevereiro é um caso a parte
    if (vPAR_IMPAR = 0  and vULTDIGANO in (0,4,8)) or --se o penúltimo dia for par e o último dígito for 0,4, ou 8
       (vPAR_IMPAR = 1  and vULTDIGANO in (2,6)) then --ou o penúltimo dia for ímpar e o último dígito for 2 ou 6 é ano bissexto 
      return 29; --então retorna 29
    else
      return 28; --senão 28
    end if;
  else
    return 30; --os outros meses têm 30 dias
  end if;
end;
Fiz rápido aqui, qualquer melhoria por favor gritem. Abrs. :)
Tineks
Rank: DBA Sênior
Rank: DBA Sênior
Mensagens: 365
Registrado em: Ter, 24 Mai 2005 2:24 pm
Localização: Araraquara - SP
Cristiano (Tineks)
Araraquara - SP

E ai Jefries, beleza?

brow, eu não sei se existe um comando no padrão ansi q venha servir para os o bancos...

pro oracle você pode usar esse aqui

Selecionar tudo

SQL> select last_day(trunc(sysdate)) from dual
  2  /

LAST_DAY(TRUNC(SYSDATE))
------------------------
28/2/2011
agora pro sql server a coisa já muda, esse exemplo abaixo deve funcionar, peguei ele na net...

Selecionar tudo

DECLARE @date DATETIME
    SET @date='2007-02-03'
SELECT DATEADD(dd, -DAY(DATEADD(m,1,@date)), DATEADD(m,1,@date))
            AS LastDayOfMonth

LastDayOfMonth
-----------------------
2007-02-28 00:00:00.000

(1 row(s) affected)
a busca dessa data não pode ser feita dentro do seu aplicativo?

[]s!!
Avatar do usuário
dr_gori
Moderador
Moderador
Mensagens: 5024
Registrado em: Seg, 03 Mai 2004 3:08 pm
Localização: Portland, OR USA
Contato:
Thomas F. G

Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered

Eu consigo fazer isso com essa simples função:

Selecionar tudo

TRUNC( TO_DATE( '15/'||suadata, 'DD/MM/YYYY') + 20 , 'MM' ) -1 
O que isso faz:
1. Pega a sua data no formato MM/YYYY (exemplo, '08/2010').
2. Coloca dia 15 pra essa data. (vai ficar 15/08/2010)
3. Soma 20 (dai isso vai acabar indo pro proximo mês, dia 04/09/2010)
4. Faz TRUNC na data pelo mês (MM)... dai a data vai pra 01/09/2010
5. Subtrai 1, ficando 31/08/2010 :-D

Veja: com AGOSTO

Selecionar tudo

SQL> SELECT TRUNC( TO_DATE( '15/'||DT, 'DD/MM/YYYY') + 20 , 'MM' ) -1 DATA
  2  FROM (
  3        select '08/2010' DT   -- ESTE É O PARAMETRO - AGOSTO 2010
  4        from dual
  5       )
  6  /

DATA
--------
31/08/10

SQL> 
Agora com Dezembro/2010

Selecionar tudo

SQL> SELECT TRUNC( TO_DATE( '15/'||DT, 'DD/MM/YYYY') + 20 , 'MM' ) -1 DATA
  2  FROM (
  3        select '12/2010' DT   -- ESTE É O PARAMETRO - DEZEMBRO 2010
  4        from dual
  5       )
  6  /

DATA
--------
31/12/10

SQL> 
Teste com FEVEREIRO normal

Selecionar tudo

SQL> SELECT TRUNC( TO_DATE( '15/'||DT, 'DD/MM/YYYY') + 20 , 'MM' ) -1 DATA
  2  FROM (
  3        select '02/2011' DT   -- ESTE É O PARAMETRO - FEVEREIRO 2011
  4        from dual
  5       )
  6  /

DATA
--------
28/02/11

SQL> 
Teste com Fevereiro BISSEXTO

Selecionar tudo

SELECT TRUNC( TO_DATE( '15/'||DT, 'DD/MM/YYYY') + 20 , 'MM' ) -1 DATA
  2  FROM (
  3        select '02/2012' DT   -- ESTE É O PARAMETRO - FEVEREIRO 2012 - BISEXTO !!!
  4        from dual
  5       )
  6  /

DATA
--------
29/02/12

SQL> 
FUNCIONA :-D

:-o

A unica função que eu to usando é TRUNC, mas isso pode ser facilmente substituído por uma outra que coloca dia 01 sempre.
burga
Rank: DBA Pleno
Rank: DBA Pleno
Mensagens: 232
Registrado em: Qui, 26 Nov 2009 1:05 pm
Localização: SP
Ricardo H. Tajiri

Se quer que fique independente do SGBD utilizado, calcule a data diretamente pela aplicação... As funções de manipulação de data do Oracle e do SQL Server são muito diferentes entre si pra você fazer algo genérico...
burga
Rank: DBA Pleno
Rank: DBA Pleno
Mensagens: 232
Registrado em: Qui, 26 Nov 2009 1:05 pm
Localização: SP
Ricardo H. Tajiri

Complementando meu post acima:

Outra opção, como o ballboas "falou", é você implementar uma função em cada banco com o mesmo nome e parâmetros, e assim você consegue alcançar esse nível "genérico", através da utilização destas funções.
gfkauer
Rank: DBA Sênior
Rank: DBA Sênior
Mensagens: 389
Registrado em: Ter, 27 Jul 2010 1:34 pm
Localização: Sapiranga - RS
Contato:
Quem falou que programar era fácil??

Quanto mais dificil for a implementação mais valorizado seu trabalho será!

Acessem: www.gfkauer.com.br

Baseado no que o Burga mencionou acima, ao invés de criar 2 funções, uma para cada banco, apenas crie uma no sqlServer chamada de last_day. Como no oracle ela já existe não precisaria criar uma customizada para isso.
Jefries
Rank: Estagiário Sênior
Rank: Estagiário Sênior
Mensagens: 14
Registrado em: Dom, 09 Mai 2010 4:20 pm
Localização: Sorocaba

É pessoal, isso

-----> to_date ---- não funciona no SQL Server


------> trunk ------ isso também não

rsrs

em fim o problema é que eu tenho que resolver apenas com comando SQL.

e não é possível criar funções no SQL Server por que para funcionar nos dois bancos...

por que?

por que no SQL Server, você tem que chamar a função colocando o nome do esquema antes
por exemplo:

dbo.nome_da_funcao(parametros...


Bom pessoal valeu pela ajuda, mas não vai ter jeito!

Valeu a todos!
Avatar do usuário
dr_gori
Moderador
Moderador
Mensagens: 5024
Registrado em: Seg, 03 Mai 2004 3:08 pm
Localização: Portland, OR USA
Contato:
Thomas F. G

Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered

Mesmo se a gente não usar nenhuma função, e te mostrar uma forma de fazer isso apenas com + - * /, você não vai conseguir implementar no SQL*Server porque vai ter alguma sintaxe diferente no comando select. :-(

O jeito é fazer isso dentro da aplicação OU como os colegas disseram: crie uma função em cada banco, coloca sinônimos pra não ter que colocar OWNER na frente, etc.
Jefries
Rank: Estagiário Sênior
Rank: Estagiário Sênior
Mensagens: 14
Registrado em: Dom, 09 Mai 2010 4:20 pm
Localização: Sorocaba

SQL Server não aceita sinonimo, tem que usar OWNER.

Mesmo assim muito obrigad a todos.
burga
Rank: DBA Pleno
Rank: DBA Pleno
Mensagens: 232
Registrado em: Qui, 26 Nov 2009 1:05 pm
Localização: SP
Ricardo H. Tajiri

Gambiarra mór:

Crie o esquema "dbo" (pegando do seu exemplo) no Oracle e crie a função dentro dele, assim você usa o owner nos dois bancos pra chamar as funções...
Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

Não faz sentido esse requisito de ter que usar o mesmo código nos dois bancos. Você vai ter que implementar códigos diferentes.

Seja por function, seja no SQL. Se for o caso, escreva o SQL usando last_day() no Oracle, e faça como for preciso fazer no SQL Server, e depois encapsule a lógica numa view. A view será a camada de abstração.
Responder
  • Informação
  • Quem está online

    Usuários navegando neste fórum: Nenhum usuário registrado e 15 visitantes