segunda-feira, 4 de fevereiro de 2019

Uso da cláusula HAVING

Quando usamos a clausula GROUP BY temos por vezes a tendencia em usar o HAVING para especificar uma condicao simples como especificado abaixo: 

SELECT 

  META_GB.COD_PROJINT, 

  META_GB.COD_METPADRAO, 

  METAPADRAO.DES_METPADRAO, 

  METAPADRAO.COD_UNIDMED, 

  UNIDMED.SIG_UNIDMED 

FROM 

  META_GB, 

  METAPADRAO, 

  UNIDMED 

WHERE 

  ( META_GB.COD_METPADRAO = METAPADRAO.COD_METPADRAO ) and 

  (METAPADRAO.COD_UNIDMED = UNIDMED.COD_UNIDMED) 

GROUP BY 

  META_GB.COD_PROJINT, 

  META_GB.COD_METPADRAO, 

  METAPADRAO.DES_METPADRAO, 

  METAPADRAO.COD_UNIDMED, 

  UNIDMED.SIG_UNIDMED 

HAVING ( META_GB.COD_PROJINT = :Param1 ) 



ao inves de usar a clausula having para condicionar coloque esta condicao na clausula WHERE como especificado abaixo 



SELECT 

  META_GB.COD_PROJINT, 

  META_GB.COD_METPADRAO, 

  METAPADRAO.DES_METPADRAO, 

  METAPADRAO.COD_UNIDMED, 

  UNIDMED.SIG_UNIDMED 

FROM 

  META_GB, 

  METAPADRAO, 

  UNIDMED 

WHERE 

  ( META_GB.COD_METPADRAO = METAPADRAO.COD_METPADRAO ) and 

  (METAPADRAO.COD_UNIDMED = UNIDMED.COD_UNIDMED) and 

  ( META_GB.COD_PROJINT = :Param1 ) 

GROUP BY 

  META_GB.COD_PROJINT, 

  META_GB.COD_METPADRAO, 

  METAPADRAO.DES_METPADRAO, 

  METAPADRAO.COD_UNIDMED, 

  UNIDMED.SIG_UNIDMED 



obs: caso a condicionante seja de grupo esta tem que ficar obrigatoriamente na clausula HAVING 

Sql relacionada com a primeira letra

query1.active := false;
query1.sql.clear;
query1.sql.add('select * from estrucpr where upper(portugues)like "LETRA%" ');
query1.active:= true;
PRIMEIRA LETRA "LETRA%"

ULTIMA LETRA "%LETRA"

QUE CONTENHA A LETRA "%LETRA%" 

Sql pesquisando utilizando um edit

query1.active := false;
query1.sql.clear;
query1.sql.add('select * from teste where nome = "' + edit1.Text + '"');
query1.active:= true;

Selecionando registros de uma tabela que não existam em outra tabela

(SELECT * FROM ,  

  WHERE . = . 

  AND . = 'AP' 

  MINUS 

(SELECT * FROM @remoto1, @remoto1 

  WHERE @remoto1. = @remoto1. 

  AND @remoto1. = 'AP' 



obs: todos os campos retornados no SELECT secundário deverá conter os mesmos campos do SELECT primário

Procura com mais de um Banco de Dados

edit1.text:= dbcombobox1.Text;
QueryPrinc.active := false;
QueryPrinc.sql.clear;
QueryPrinc.sql.add('select * from estrucpr where portugues = "' + edit1.Text + '"');
QueryPrinc.active:= true;

if DBcodEl.text=DBcodEl.text then
edit2.Text:= DBcodEl.Text;

QuerySin.active := false;
QuerySin.sql.clear;
QuerySin.sql.add(' select * from sinonimo where sin_est_id = "' + edit2.text + ' "');
QuerySin.active:= true;

 if DBcodEl.text=DBcodEl.text then
edit3.Text:= DBcodEl.Text;

QueryPropFis.active := false;
QueryPropFis.sql.clear;
QueryPropFis.sql.add('select * from FIQU_PRO where fiqu_id = "' + edit3.Text + '"');
QueryPropFis.active:= true;

Otimizações no SQL

As dicas abaixo foram testadas essencialmente com Oracle

1) Todas as vezes que for utilizar um SQL que possua condições de OR, é mais aconselhável e mais rápido utilizar IN, como no exemplo: 

AO INVÉS DE 

  Select * from projint where sit_projint = ‘AI’ or sit_projint = ‘EL’ 

COLOQUE 

  Select * from projint where sit_projint IN (‘AI’,‘EL’); 

2) Quando existem duas ou mais condições AND juntas, especifique primeiro sempre a que possui o maior limite de ocorrências 

AO INVÉS DE 

  select count(*) from pessoa where sit_pessoa = 11 AND cod_munic > 1100155 

COLOQUE 

  select count(*) from pessoa where cod_munic > 1100155 AND sit_pessoa = 11 

3) Quando existem duas ou mais condições OR juntas, especifique primeiro sempre a que possui o maior limite de ocorrências 

AO INVÉS DE 

  select count(*) from pessoa where cod_munic > 1100155 OR sit_pessoa = 11 

COLOQUE 

  select count(*) from pessoa where sit_pessoa = 11 OR cod_munic > 1100155 

4) Tenha cuidado com o sinal de <> 

AO INVÉS DE 

  select count(*) from pessoawhere cod_munic < > 1100155 

COLOQUE 

  select count(*) from pessoawhere cod_munic < 1100155 OR cod_munic > 1100155 

Extraindo o ano, mês ou dia de uma data via SQL

Select * from nome_tabela where extract(year from campo_data) = 2019

Você pode extrair o mês (MONTH) ou o dia (DAY). 

Excluindo registros de uma tabela

Desejo excluir registro de uma tabela que dependem da existência de outros de outra(s) tabela(s), como fazer? 

DELETE FROM  
 WHERE (, ,
  IN 
(SELECT , , 
 FROM a,
  WHERE a. = b. 
  AND b. = 'AP' ) 

Criando tabelas via SQL

Inclua na seção uses: dbTables

- Coloque um TButton no form;

- Escreve no OnClick do Button como abaixo:

procedure TForm1.Button1Click(Sender: TObject);
var
  Q: TQuery;
begin
  Q := TQuery.Create(Application);
  try
     Q.DatabaseName := 'SF';
     with Q.SQL do begin
        Add('Create Table Funcionarios');
        Add('( Codigo AutoInc,');
        Add(' Nome Char(30),');
        Add(' Salario Money,');
        Add(' Depto SmallInt,');
        Add(' Primary Key (Codigo) )');
     end;
     Q.ExecSQL;
  finally
     Q.Free;
  end;
end;

Consultar por mês de um campo data

Problema:

Tenho um cadastro de clientes com Codigo, Nome, DataNasc, etc.

Preciso fazer uma consulta onde apareceão apenas os clientes que fazem aniversário em determinado mês. Como fazer?

Solução:

Use uma Query como abaixo:

- Coloque no form os seguintes componentes:

  * TQuery

  * TDataSource

  * TDBGrid

  * TEdit

  * TButton

- Altere as propriedades dos componentes como abaixo:

  * Query1.DatabaseName = (alias)

  * DataSource1.DataSet = Query1

  * DBGrid1.DataSource = DataSource1

 - Coloque o código abaixo no evento OnClick de Button1:

  Query1.Close;
  Query1.SQL.Clear;
  Query1.SQL.Add('select * from dCli');
  Query1.SQL.Add('where extract(month from DataNasc) = :Mes');
  Query1.ParamByName('Mes').AsInteger := StrToInt(Edit1.Text);
  Query1.Open;
- Execute. Digite um número de 1 a 12 no Edit e clique no botão.

Consultando entre datas utilizando SQL

If DateTimePicker2.Date < DateTimePicker1.Date Then 
begin 
   ShowMessage('Intervalo de datas inválido, a data inicial é maior que a data final!'); 
   DateTimePicker2.Date := DateTimePicker1.Date; 
end 
Else 
begin 
   Inicio := DateToStr(DateTimePicker1.Date); 
   Final := DateToStr(DateTimePicker2.Date); 
   Query1.Close; 
   Query1.SQL.Clear; 
   Query1.SQL.Text := 'SELECT Nome,Empresa,FoneRes,FoneCom,Mala FROM Contatos WHERE     Data >=:pInicial and Data<=:pFinal ORDER BY Nome'; 
   Query1.ParamByName('pInicial').AsDateTime := StrToDate(Inicio); 
   Query1.ParamByName('pFinal').AsDateTime := StrToDate(Final); 
   Query1.Prepare; 
   Query1.Open; 
   DBGrid3D1.SetFocus 
end;

Label3.Caption := 'Total de contatos: ' + IntToStr(Query1.RecordCount) 

Consulta SQL que usa a data do sistema

Problema:

Preciso fazer uma consulta com SQL que me retorne todos os registros em que o valor de um campo do tipo data seja igual ou anterior à dada do sistema. Como fazer?

Solução:

Query.Close;
Query.SQL.Text := 'select * from Tabela where CampoData <= :Hoje';
Query.ParamByName('Hoje').AsDate := Date;
Query.Open;
Observações

Este exemplo foi testado com tabelas Paradox, mas deve funcionar na maioria dos bancos de dados com pouca ou nenhuma alteração

Como usar a cláusula UNION em um Query

O uso do componente TQuery gera muitas vantagens e economiza muitas linhas de programação. Mas muitas vezes nos deparamos com situações que parecem não ser resolvidas com sentenças SQL. Vejamos um exemplo:

Você possui 2 tabelas (VendasExternas e VendasInternas) e deseja fazer um resumo de todas as vendas de um vendedor chamado Marcos. Se você usar a sentença

SELECT Nome, Valor FROM VendasExternas, VendasInternas
WHERE Nome = 'Marcos'
você vai obter como resultado uma query com 4 campos (Nome, Valor, Nome_1 e Valor_1) e um resultado bem confuso para ser manipulado.

Para resolver o problema, você poderá usar a sentença

SELECT Nome, Valor FROM VendasExternas
WHERE Nome = 'Marcos'
UNION ALL
SELECT Nome, Valor FROM VendasInternas
WHERE Nome = 'Marcos'
A sentença acima pede para que sejam identificados as vendas de Marcos na tabela VendasExternas, as vendas de Marcos na tabela VendasInternas e que o resultado da primeira seja unido com o resultado da segunda produzindo uma query com apenas 2 colunas. 

Bloco PL/SQL para inserção de dados

Pergunta 
Criar um bloco pl/sql que insira um novo dep na tabela s_dept 

- use a sequencia s_dept_id para o campo id da tabela 

- solicite ao usuario o nome do dep 

- insira valores nulos p/ o campo region_id 

Resposta 
-> no banco de dados... 
create or replace 
procedure insere_departamento (v_nome char) is 
v_id number; 
begin 
  SELECT sequenciaID.NEXTVAL INTO v_id FROM DUAL; 
  insert into tabela (id,dep,region_id) 
  values (v_id,v_nome,null); 
end insere_departamento; 

-> no delphi... 

- coloque o objeto TStoredProc dentro do formulario que ira disparar esta procedure; 
- no evento que voce quiser que dispare coloque o seguinte codigo: 
 var 
  v_nome : String[50]; 
  begin 
{caso vc queira informar o nome do departamento atraves de uma caixa de dialogo} 
  V_nome := inputbox('Informe o nome do departamento.','Depto:',''); 
  .Params[0].AsString := v_nome; 
{caso vc queira buscar o nome atraves de um TEdit já preenchido} 
  .Params[0].AsString := .Text; 
  .ExecProc; 
  end; 
  

Alterando parcialmente o conteúdo da prop.SQL de uma Query

Vamos supor que você tenha uma instrução SQL em uma Query como a seguinte:

SELECT IDCliente, cli_Nome, cli_DataNasc, cli_Sexo
FROM Cliente
WHERE ( IDCliente < 1000 )
AND ( cli_Sexo = 'M' ) (*)
ORDER BY cli_Nome
Para alterar somente a quarta(*) linha do SQL você pode fazer assim:

with qryCliente do
  begin
  if Active then Close;
  SQL[3] := 'AND ( cli_UF = 'ES') OR ( cli_UF = 'RJ' )'; // ou SQL[3] := ' ';
  Open;
  end;