Select SQL uma Visao Geral LINGUAGEM ESTRUTURADA DE
Transcrição
Select SQL uma Visao Geral LINGUAGEM ESTRUTURADA DE
Select SQL uma Visao Geral LINGUAGEM ESTRUTURADA DE CONSULTA O programador que chega no Visual FoxPro , vindo de linguagens padrao Xbase (Foxpro 2.x, Clipper , Dbase, etc) acaba encontrando na linguagem SQL , uma grande aliada, e apesar dos comandos serem diferentes do Xbase , existe muita coisa que continuará igual, porque o Visual FoxPro possui linguagem SQL de forma nativa, basta abrir a Janela de comandos e sair digitando instrucoes SQL. Nos tempos de Clipper por exemplo, o programador estava acostumado a fazer "perguntas" para o Banco de dados usando os comandos USE , SET FILTER , SET RELATION , SET ORDER , BROWSE etc. Tudo isto continua exatamente igual no Visual FoxPro. Com a linguagem SQL você também faz tudo isto, e mais , com resultados bem melhores, e com a vantagem que já estaremos nos preparando para desenvolver uma aplicacao cliente/servidor. O que devemos observar, e nunca confundir, é SQL a linguagem , com SQL SERVER , que é um Banco de Dados da Microsoft. Mas nao nos preocupemos com este Banco de dados SQL agora, porque dentro do Visual FoxPro, no SQL nativo, existe o "assistente de upsizing do Sql Server" que vai se encarregar de criar um Banco de dados SQL Server , aonde podemos mover dados locais (DBF) para um servidor remoto, transformando as tabelas de base local (DBF) e suas visualizacoes locais, em tabelas de base remota e visualizacoes remota, migrando assim, de um aplicativo local (Prg, Dbf) para um aplicativo cliente/servidor (Web). Alguns conceitos , como o de "abrir"uma tabela de dados, irao mudar o conceito, porque passaremos a nos preocupar com um servidor remoto, e em se falando de servidor remoto, falaremos entao em fazer "conexao" com uma fonte de dados. Já fomos muito além do que pretendiamos nesta breve introdução. Voltando a uma aplciacao local, vamos nos deter na instrucao SQL SELECT ou SELECT SQL, que é muito poderosa, e podemos sair escrevendo ela dentro da janela de comandos. Select é a ligítima instrução de consulta, e ao escrever precisamos : definir qual a pergunta deve ser respondida pelo banco de dados (tabela) e o que é que queremos saber do banco (tabela). Create PDF files without this message by purchasing novaPDF printer (http://www.novapdf.com) Exemplificando : Uma pergunta do tipo : Qual minha lista de devedores ? , nao seria nada criativo, e seria bem melhor se fosse perguntado por exemplo, "Preciso saber nome, endereco, e quando cada um dos meus clientes está devendo, ordenado por data do vencimento" Tudo o que precisamos é aprender a perguntar ao banco de dados (tabela). Nos exemplos que colocarei, deve ficam bem clarom que sempre existirao diversas formas para se atingir um objetivo, e vamos usar a que mais fácil parecer ao aluno. A partir daqui, imaginemos que existe uma tabela de nome "CLIENTES" com os camposque passaremos a nos referenciar nos exemplos. Então vamos a parte bem prática : Perguntando e Respondendo : . Quero todos os dados de todos os clientes , nao importa a ordem. Resposta Select * from clientes O sinal * indica todos (todos os campos da tabela) Já que nenhuma filtragem foi solicitada, todos os registros da tabela serao mostrados. Antes mesmo de continuar, é interessante lembrar que os comandos VFP podem ser escritos em mais de uma linha, e o sinal ; (Ponto e virgula) deve ser colocado ao final de uma linha, indicando que o comando continua na proxima linha. .Quero o nome de todos os clientes , independente de ordem. Resposta Select nome as nome_do_cliente from clientes Nome é o próprio nome do campo, nome_do_cliente , é como eu quero que saia no cabeçalho da consulta. .Quero o nome da empresa e o nome do contato, de todos os clientes, ordenado por nome da empresa. Create PDF files without this message by purchasing novaPDF printer (http://www.novapdf.com) Resposta Select nome_empresa , nome_contato from clientes order by 1 By 1 significa que vai sair em ordem pelo campo 1 da lista (Nome_empresa) . Quero a regiao , nome da empresa e o nome do contato, de todos os clientes, ordenados por regiao e pelo nome da empresa. Resposta Select regiao,nome_da_empresa,nome_contato; from clientes order by regiao,nome_da_empresa Na clausula order by, se precisarmos ordenar por mais campos, basta escreve-los, separando por virgulas, e evidentemente que estará uma ordem dentro da outra. No exemplo acima, os nomes das empresas estarao em ordem crescente dentro de cada regiao. .Quero a lista de todas as regioes onde tenho meus clientes. Esta pergunta, vai nos fazer usar de uma clausula GROUP BY. Acontece que existem muitos registros que serao mostrados e tem uma grande quantidade de regioes diferentes. Resposta Select regiao from clientes group by regiao E tudo isto porque : porque queremos que o nome de uma regiao saia apenas uma vez, e por isto , usamos o agrupamento (Group By) . Quero saber quantos clientes eu tenho em cada regiao. Esta já é uma pergunta mais completa. Resposta Select regiao , count(regiao) as contagem; from clientes group by regiao Create PDF files without this message by purchasing novaPDF printer (http://www.novapdf.com) Count(regiao) : está indicando que eu quero uma contagem (Funcao Count()) As contagem : foi necessário para identificar um cabeçalho para este total que será mostrado. . Quero saber o nome da empresa e nome do contato de todos os clientes , ordenado pelo nome da empresa. Resposta Select nome_empresa, nome_contato; from clientes order by 1 . Quero saber quantos clientes eu tenho por regiao, porém como podem existir regioes em "branco", nao quero que apareça aquele cabeçalho "regiao sem nome", e para mostrar uma busca mais clara, escrevo : Resposta Select IIF(not empty()regiao), regiao,; "regiao nao encontrada") as regiao , count(regiao); as contagem from clientes group by regiao A função IIF possibilita que se o campo "regiao" nao estiver vazio, utilizamos o seu conteudo, senao colocamos um "regiao nao informada" no registro. . Agora umaa pergunta mais complexa. Na tabela clientes, existe um outro campo chamado Valor_maior , indicando de quanto foi o valor do maior pedido efetuado por um cliente. Quero entao saber qual foi o valor mais alto já pedido em cada regiao, da regiao com valor mais baixo, até a regiao com valor mais alto. Resposta Select regiao, max(valor_maior) as maior_pedido; from clientes group by regiao order by 2 Sairão as regioes, e dentro das regioes, cfe solicitado, em ordem do menor valor ao maior valor. . Mas no exemplo anterior, veio muita coisa, e eu quero montar o meu ranking top 10, com as Create PDF files without this message by purchasing novaPDF printer (http://www.novapdf.com) 10 regioes que tiverem os maiores valores de pedidos, da regiao com o maior pedido para a regiao com menor pedido (ou seja , ordem decrescente) Resposta Select top 10 regiao, max(valor_maior); as maior_pedido from clientes; group by regiao order by 2 desc Ficou tudo mais ou menos igual, apenas que a clausula TOP 10 indica que serao mostrados os 10 maiores. Importante : Quando voce usa a clausula TOP , é "obrigatório" definir uma "ordem" (order by) . Agora, uma coisa mais complexa ainda. A empresa vai fazer uma promocao para 20% das regioes de maior valor de pedido feito, e veja como solicito isto. Resposta Select top 20 percent regiao,; max(valor_maior) as maior_pedido; from clientes group by regiao order by 2 desc Neste caso, como existe a clausula percent , o 20 significa 20 % . Preciso saber o nome dis meus clientes na regiao de Santa maria Resposta Select nome_empresa from clientes ; where regiao = "Santa maria" A clausula Where, faz a filtragem mostrando apenas clientes que seja da regiao citada (Santa Maria, no caso) . Além de "Santa Maria"também quero, "Santa Rosa" Resposta Create PDF files without this message by purchasing novaPDF printer (http://www.novapdf.com) Select nome_empresa, regiao from clientes; where regiao = "Santa Maria" or ; regiao = "Santa Rosa" A unica diferença em relaçao a consulta anterior, é que esta pede duas regioes, entao na filtragem uso a clausula OR ( OU ) . A empresa precisa agora da lista com os nomes dos clientes em 5 regioes : "sp", "rj" , "pa" , "pr" e "ms" . Resposta Select nome_empresa , regiao from clientes; where inlist (regiao,"sp","rj","pa","pr","ms") Acrescentou-se a clausula INLIST e nomeamos as regioes solicitadas. Importante : Com criatividade, dentro de um prg, podemos informar quais as 5 regioes, jogar para variáveis rg1,rg2,rg3.rg4,rg5 e escrever o select assim : Select nome_empresa , regiao from clientes; where inlist(regiao,rg1,rg2,rg3,rg4,rg5) Mais .. No caso INLIST (regiao "sp","rj","pa","pr","ms") e se esta lista fosse maior !! Neste caso use a funcao INLIST() , voce diz para ela qual é o campo e qual a lista de valores que voce deseja procurar, e estará resolvido. . A empresa está fazendo uma grande promocao para os clientes, e quer presentear aqueles que estiverem entre os registros 10 e 20 do cadastro. Resposta Select recno(), nome_empresa from clientes; where between(recno(),10,20) Estamos entao usando a funcao RECNO() , e na filtragem colocando BETWEEN(recno(),10,20) indicando que devem ser mostrados apenas os clientes entre o registro 10 e o 20 ( 10,11,12,13,14,15,16,17,18,19,20) Create PDF files without this message by purchasing novaPDF printer (http://www.novapdf.com) . Agora a empresa quer saber o nome dos clientes, cujo nome da empresa começa com a letra "S" Resposta Select * from clientes ; where nome_empresa like "S%" Apenas foi usada na filtragem a condicao LIKE, indicando que só vai mostrar, do nome_empresa , os que iniciarem por "S" (% significa que os restantes caracteres do nome nao importa) . Agora, a empresa vai convocar uma reuniao com todos os gerentes dos clientes. Precisa entao uma listagem com o nome dos gerentes e o telefone. Resposta Select gerente, telefone from clientes; where upper(cargo) like "%gerente%" Veja : No campo "cargo" vai estar gravado por exemplo, "Gerente de vendas" ou "Socio gerente de filial" , exemplos apenas, e neste caso o LIKE "%gerente%" vai pegar qualquer tipo de ocorrencia, desde que em algum lugar esteja gravado a palavra "gerente" (Por isso o sinal de % antes e depois ) Upper(cargo) significa que ele vai passar o conteudo do campo CARGo para maiusculo, para evitar problemas nas comparacoes, maiusculas e minusculas. . A empresa quer saber : Listar as regioes onde tem mais de 2 clientes, desconsiderando aqueles clientes que nao possuem regiao informada. Resposta Select regiao, count(*) as contagem; from clientes; where not empty(regiao); group by regiao having contagem > = 3 Create PDF files without this message by purchasing novaPDF printer (http://www.novapdf.com) Veja : Count(*) joga o resultado para uma variavel CONTAGEM e no final a clausula HAVING faz um filtro, especificando que a contagem precisa ser > ou igual a 3. . A empresa quer ver a lista de clientes, datas de pedidos de cada um, ordenada pelo nome da empresa e pela data do pedido. Resposta Select clientes.nome_empresa,; pedidos.data_pedido; from clientes,pedidos; where clientes.codigo_cliente = pedidos.codigo_cliente; order by clientes.nome_empresa,pedidos.data_pedido Existem duas tabelas ; a tabela Clientes e a Pedidos e serão consultadas em paralelo. A tabela pedidos possui os pedidos todos, e a clientes os nomes dos clientes. Na clausula from , preciso referenciar as duas tabelas. Na clausula WHERE , voce estabeleceu que as duas tabelas vao correr juntas, sendo unidas pelo campo codigo_cliente que existe nas duas tabelas. E o order By , especifica que a ordem de amostragem será por nome do cliente, e dentro de cada cliente por data do pedido. . A empresa precisa ver a lista de clientes e datas de pedidos de cada um (duas tabelas) ordenada pelo nome da empresa e pela data do pedido. Resposta Select a.nome_empresa, b.data_pedido; from clientes a , pedidos b; where a.codigo_cliente = b.codigo_cliente; order by nome_empresa,data_pedido Só o que mudou foi o fato de terem sido associadas a cada tabela, as letras A e B , A para Clientes e B para Pedidos. (A e B sao conhecidos como local aliás) Create PDF files without this message by purchasing novaPDF printer (http://www.novapdf.com) . Agora a empresa precisa ver a lista de clientes e datas de pedidos de cada um, ordenada pelo nome da empresa e pela data do pedido. Resposta Select clientes.nome_empresa,pedidos.data_pedido; from clientes; inner join pedidos on ; clientes.codigo_cliente = pedidos.codigo_cliente; order by clientes.nome_empresa,pedidos.data_pedido Sobre o INNER JOIN Uma nova forma de fazer JUNÇÃO entre tabelas. Temos duas tabelas , uma está a esquerda (clientes) e outra do lado direito (pedidos). Com o INNER JOIN , vamos saber, quais os registros do lado esquerdo que encontraram pelo menos 1 registro equivalente do lado direito. Assim sendo, só veremos os clientes que efetivaram algum pedido. . A empresa quer a mesma coisa do exemplo anterior, só que agora, esta lista tem que trazer todo mundo, mesmo que o cliente nao tenha feito pedido algum. Resposta Select clientes.nome_cliente, pedidos.data_pedido; from clientes; LEFT JOIN pedidos; on clientes.codigo_cliente = pedidos.codigo_cliente; order by clientes.nome_empresa,pedidos.data_pedido Veja : Substituindo INNER JOIN pelo LEFT JOIN , faz com que a consulta retorne todos os registros do lado esquerdo da juncao, independente de encontrar registro equivalente do lado direito. . Agora a empresa quer saber, a quantidade total de pedidos atendidos por cada funcionário. A lista tem que ser ordenada pelo nome dos funcionários. Vamos colocar outra tabela na jogada, a tabela "funcionários" Create PDF files without this message by purchasing novaPDF printer (http://www.novapdf.com) Resposta Select funcionarios.primeiro_nome_do_funcionario ,; count(pedidos.codigo_cliente) as qtde_total_pedidos; from pedidos; inner join funcionarios ; on funcionarios.codigo_funcionario = pedidos.codigo_funcionario; group by funcionarios.primeiro_nome_do_funcionario; order by funcionarios.primeiro_nome_do_funcionario É muito fácil de entender, porque todas as clausulas já foram praticadas. . Bem , nesta lista nao aparecem todos os funcionários, está faltando alguns, e a empresa quer que apareçam. Então : Resposta Select funcionarios.primeiro_nome_do_funcionario,; count(pedidos,codigo_cliente) as qtde_total_pedidos ; from pedidos; right join funcionarios on funcionarios.codigo_funcionario; = pedidos.codigo_funcionario; group by primeiro_nome_do_funcionario; order by primeiro_nome_do_funcionario Falamos a alguns exercicios atrás, que LEFT JOIN traz todos os registros do lado esquerdo da relacao, lembra. Pois entao, também temos o RIGHT JOIN , que traz todos os registros do lado direito da relacao, ou seja , neste caso, traz todos os funcionarios , independente de existir algum pedido por ele atendido ou nao. No exercicio anterior, aqueles que nao atenderam a nenhum pedido, ficaram de fora. . Agora a empresa quer saber quem sao os funcionarios que nao atenderam nenhum pedido. Resposta Select funcionarios.primeiro_nome_do_funcionario; from funcionarios; where funcionarios.codigo_funcionario not IN ; Create PDF files without this message by purchasing novaPDF printer (http://www.novapdf.com) (select funcionarios.codigo_funcionario from pedidos) Agora voce vai aprender a usar sub-queries (Sub consulta). A essência da pergunta é : da lista de funcionários, quem é que nao tem nenhum pedido atendido ! Fazemos entao o select na tabela funcionarios, filtrando por somente aqueles que o codigo_funcionario nao estiver na tabela pedidos. Inicialmente a sub consulta é executada, para se saber quais sao os codigo_funcionario na tabela de pedidos, e em seguida é executada a consulta na tabela de funcionarios, procurando somente os codigo_funcionario que nao estao no resultado da primeira consulta. Quantas linhas de comando voce terá ganho em clipper, para fazer uma consulta destas ! Algumas dezenas com certeza. . A empresa agora quer fazer um agrado para os funcionarios mais fiéis e produtivos. Para isto, precisa saber quem sao os funcionarios que atenderam mais de 100 pedidos ou que foram contratados de 1993 até hoje. Resposta Select alltrim(funcionarios.primeiro_nome_do_funcionario); +" "+funcionarios.ultimo_nome_do_funcionario; from pedidos; inner join funcionarios on ; funcionarios.codigo_funcionario = ; pedidos.codigo_funcionario ; group by funcionarios.primeiro_nome_do_funcionario; having count(pedidos.codigo_pedido) > 100 ; union; select alltrim(primeiro_nome_do_funcionario)+; " "+ultimo_nome_do_funcionario from; funcionarios; where year(data_admissao) > = 1993 Parece que a coisa complicou, mas nao é bem assim. Verifique, temos duas grandes condicoes : 1 : Funcionários que atenderam mais de 100 pedidos. Voce já sabe fazer isso através do Create PDF files without this message by purchasing novaPDF printer (http://www.novapdf.com) having e do count() ( A novidade aqui, é que o count() pode ser usado diretamente junto do having) 2 : Funcionários que foram contratados de 1993 até o dia atual. ( A unica novidade aqui é o uso da funcao YEAR() , para ver o ano da data da contratacao. A grande novidade, está na clausula UNION. Esta clausula UNE consultas. Entao o ideal é criar a primeira consulta, e testaremos. Funcionou ? criamos a segunda consulta, e testamos , funcionou ? Unimos entao as duas com a clausula UNION. Ela junta os registros das duas consultas , e despreza registros repetidos ( Neste caso, o funcionário que atende aos dois critérios) Se quiser também os registros repetidos, basta usar UNION ALL. Como um a consulta é agregada a outra, será necessário que ambas produzam uma estrutura igual, caso contrárioé gerado um erro. . Agora a empresa quer uma listagem, uma unica listagem, com nome de todos os funcionários e contatos de clientes, para mandar um cartao de natal no final do ano. Resposta Select padr(primeiro_nome_do_funcionario,30," ") ; as nome , "funcionario" as tipo ; from funcionarios; union; select nome_do_contato, "cliente" as tipo; from clientes; order by 2 , 1 A diferença é que neste caso, somaremos registros de duas tabelas diferentes. Já falamos que a estrutura das tabelas tem de ser iguais. Entao o campo primeiro_nome_do_cliente na tabela funcionários é do tipo Caracter, tamanho 10. Já o campo nome_do_contato na tabela clientes também é do tipo Caracter, só que o tamanho é 30, e agora como fica ! Lembre-se de uma regra : A primeira consulta é que dita a estrutura das demais em uma instrucao com UNIONs ( é isso mesmo, podemos ter várias, várias consultas ligadas por vários UNIONs). Então precisamos dar um jeito no campo primeiro_nome_do_funcionario , Create PDF files without this message by purchasing novaPDF printer (http://www.novapdf.com) para que ele fique igual ao nome_do_contato. Para isto basta usar a funcao PADR() que preenche um string com um numero X de um determinado caractere, no nosso caso, preenchemos com espaços vazios, até que a string alcance o tamanho 30. Ok, agora elas já sao compatíveis. A clausula ORDER BY aqui só pode ser usada com o numero das colunas na lista, e nao pelo nome dos campos, pois podem ser completamente diferentes entre as consultas. Daqui para frente, quem quiser se especializar ainda mais, use o HELP do VFP. 21 de Agosto de 2003 Create PDF files without this message by purchasing novaPDF printer (http://www.novapdf.com)