Conceitos Básicos de SQL
Instrutor: Jefferson Machado Ximenes
SQL – Structure Query Language(Linguagem
de Consulta Estruturada).
É uma linguagem para bancos de dados
relacionais.
É uma linguagem declarativa, com o foco
centrado no resultado, onde:
◦ O usuário descreve o dado desejado, sem
especificar como obtê-lo;
◦ O SGBD determina o melhor procedimento para
realizar essa tarefa.
◦ Poupa tempo de programação, mas exige tempo
para projeto.
O Padrão ANSI
ANSI – American National Standards Institute.
◦ É uma organização americana que aprova padrões.
ISO – International Standards Organization.
◦ Aprova padrões em nível internacional.
Versões:
◦ SQL-87 – primeiro padrão ANSI SQL aceito pela ISO, em
1987.
◦ SQL-92 – padrão ANSI SQL aceito pela ISO, em 1992.
◦ SQL-99 – padrão ANSI SQL aceito pela ISO em 1999,
também conhecido como SQL-3.
É uma linguagem de definição, manipulação e
controle de dados, definida pela Microsoft
Corporation.
As instruções Transact SQL são divididas em:
◦ Instruções DDL (Data Definition Language), que
permitem criar objetos do banco de dados;
◦ Instruções DML (Data Manipulation Language), que
permitem consultar e modificar dados;
◦ Instruções DCL (Data Control Language), que
permitem definir privilégios aos usuários.
As instruções DDL definem os objetos do banco de
dados, criando, alterando ou excluindo:
◦ o banco de dados e tabelas;
◦ os índices, procedures, triggers, views e outros objetos
As instruções DDL são:
◦ CREATE <nome do objeto> - criar objetos
◦ ALTER <nome do objeto> - alterar objetos
◦ DROP <nome do objeto> - excluir objetos
◦ Obs.O usuário deverá possuir as permissões apropriadas
As instruções DML recuperam informações ou
alteram dados, permitindo consultar, inserir,
modificar e excluir dados.
As instruções DML são:
◦ SELECT - consultar dados
◦ INSERT - inserir dados
◦ UPDATE - alterar dados
◦ DELETE - excluir dados
◦ Obs.: O usuário deverá possuir as permissões
apropriadas.
As instruções DCL alteram as permissões
associadas a um usuário ou cargo do banco
de dados.
As instruções DCL são:
◦ GRANT - adiciona permissão.
◦ DENY - nega permissão.
◦ REVOKE - remove uma permissão concedida ou
negada anteriormente.
◦ Obs. O usuário deverá possuir as permissões
apropriadas.
Bancos de dados de sistema: contêm
informações sobre o servidor. São utilizados
pelo SQL Server para operar e gerenciar o
sistema.
Bancos de dados de usuário: são criados
pelos usuários para armazenar seus dados.
Também chamadas de constraints, são condições que
garantem que valores válidos sejam inseridos nas colunas e
que os relacionamentos entre as tabelas sejam mantidos.
Se dividem em:
◦ Restrição de coluna: quando a restrição se aplica a uma única
coluna da tabela.
◦ Restrição de tabela: quando a restrição faz referência a várias
colunas da tabela, mesmo que não faça referência a todas elas.
No Oracle, as constraints são:
◦ Primary Key - Define uma chave primária.
◦ Foreign Key - Define uma chave estrangeira.
◦ Unique - Define uma chave candidata.
◦ Check - Define uma restrição de domínio.
◦ Default - Define um valor default.
Constraint PRIMARY KEY:
◦ É utilizada para definir a chave primária da tabela;
◦ Impede a inclusão de valores duplicados para a
coluna.
◦ Cria um índice na coluna para melhorar o
desempenho;
◦ Uma tabela pode conter apenas uma restrição
PRIMARY KEY.
◦ Em uma chave primária concatenada, todas as
colunas presentes em uma constraint PRIMARY KEY
devem ser definidas como NOT NULL.
Constraint FOREIGN KEY:
◦ É utilizada para definir uma chave estrangeira para
a tabela;
◦ Todo valor não nulo introduzidos na coluna de uma
restrição FOREIGN KEY deve existir na coluna
referenciada;
◦ O número de colunas e tipos de dados das colunas
especificadas em uma restrição FOREIGN KEY deve
coincidir com as colunas referenciadas.
◦ Uma tabela pode conter até 253 restrições FOREIGN
KEY.
Constraint UNIQUE:
◦ É utilizada para definir a chave candidata da tabela;
◦ Impede a inclusão de valores duplicados para a
coluna.
◦ Cria um índice na coluna para melhorar o
desempenho;
◦ Uma tabela pode conter até 249 restrições UNIQUE.
Sintaxe:
◦ Constraint UNIQUE
◦ [ CONSTRAINT nome da constraint ] UNIQUE
Constraint CHECK:
◦ É utilizada para definir restrições de domínio para
as colunas de uma tabela.
◦ Uma coluna pode possuir uma única restrição
CHECK, podendo ter várias expressões lógicas
combinadas com AND e OR.
Sintaxe:
◦ [ CONSTRAINT nome da constraint ]
◦ CHECK (expressão)
O comando SELECT permite consultar dados
em uma ou mais tabelas e retorna um
conjunto de linhas e colunas, de acordo com
as cláusulas especificadas.
Cláusulas:
Sintaxe:
◦ SELECT * FROM <nome da tabela>
◦ Exemplo 1: Exibir todos os dados de todos os
pacientes.
select * from [Link]
◦ Exemplo 2: Exibir todos os dados de todos os
produtos.
select * from [Link]
Exemplo 1: Exibir código, nome e sexo de
todos os pacientes.
◦ SELECT cd_paciente, nm_paciente, tp_sexo
◦ FROM [Link]
Exemplo 2: Exibir código e nome de todos os
produtos.
◦ SELECT cd_produto, ds_produto
◦ FROM [Link]
Sintaxe:
SELECT <coluna> [AS] <alias> FROM <tabela>
Exemplo 1: Exibir o código com o título “Produto” e o
nome como “Descrição” de todos os produtos.
◦ SELECT pr.cd_produto as "Produto'",
◦ pr.ds_produto as "Descrição"
◦ FROM [Link]
Sintaxe:
SELECT DISTINCT <lista de colunas> FROM <tabela>
Exemplo 1: Exibir o código de todos os pacientes que
já foram atendidos no PA.
◦ SELECT DISTINCT cd_paciente FROM [Link]
Exemplo 2: Exibir o bairro de todos os pacientes
◦ SELECT DISTINCT nm_bairro FROM [Link]
Sintaxe:
SELECT <lista de colunas, expressão numérica>
FROM <tabela>
Exemplo 1: Exibir código, nome, custo médio e
acrescer 1,32% no custo para cada produto.
select
pr.cd_produto as codigo,
pr.ds_produto as "Descrição",
pr.vl_custo_medio as "Custo Médio" ,
(pr.vl_custo_medio*1.32)as "Custo Médio + 32%"
from [Link] pr
Sintaxe:
SELECT <lista de colunas, string> FROM <tabela>
Exemplo 1: Exibir o código , nome e uma coluna
contendo “PACIENTE PREMIUM” para todos os
paciente.
select
cd_paciente as codigo,
nm_paciente as nome,
'PACIENTE PREMIUM' AS TIPO
from [Link] p
Sintaxe:
SELECT <lista de colunas> FROM <tabela> ORDER BY <coluna>
[ASC] [DESC]
Exemplo 1: Exibir código, nome de todos os convênios, ordenados
pelo nome em ordem ascendente.
SELECT
c.cd_convenio as codigo ,
c.nm_convenio as "Convênio",
c.ds_enderco as "Endereço"
FROM [Link] c
order by c.nm_convenio asc
ou order by 2 asc
A filtragem deve ser feita utilizando-se a cláusula
WHERE.
A cláusula WHERE filtra as linhas com base em uma
condição que deve ser especificada.
A condição é representada por uma ou mais
expressões condicionais, separadas pelos operadores
lógicos AND, OR e NOT.
O formato de cada expressão condicional é:
<coluna> <operador> <valor>
Podem ser utilizados diversos operadores para
compor as expressões condicionais utilizadas.
Sintaxe:
SELECT <lista de colunas>
FROM <tabela>
WHERE <condição>
Exemplo 1: Exibir código, nome e quantidade do
produto onde esta quantidade deve esta entre 100 e
200 e em ordem descendente.
◦ SELECT
◦ pr.cd_produto as codigo,
◦ pr.ds_produto as "Descrição",
◦ PR.QT_ULTIMA_ENTRADA as Qtde
◦ FROM
◦ [Link] PR
◦ WHERE
◦ PR.QT_ULTIMA_ENTRADA >= 100 and PR.QT_ULTIMA_ENTRADA <=200
◦ order by 3 asc
◦ // PR.QT_ULTIMA_ENTRADA between 100 and 200
Exemplo 2: Exibir todos os pacientes do sexo
“F” e que more no CENTRO
select
cd_paciente as codigo,
nm_paciente as nome,
p.nm_bairro
from [Link] p
where
p.nm_bairro = 'CENTRO'
AND P.tp_sexo = 'F'
Sintaxe:
SELECT <lista de colunas>
FROM <tabela>
WHERE <coluna> [NOT] IN (<lista de
valores>)
Exemplo 1: Exibir dados dos pacientes que
residam em Manaíra ou Centro, ordenados
pelo nome em ordem ascendente.
select
cd_paciente as codigo,
nm_paciente as nome,
tp_sexo as sexo,
p.nm_bairro as Bairro
from [Link] p
where
p.nm_bairro IN ( 'CENTRO', 'MANAIRA')
Sintaxe:
SELECT <lista de colunas>
FROM <tabela>
WHERE <coluna> [NOT] BETWEEN
(<intervalo>)
Exemplo 1: Exibir todos pacientes que
nasceram entre '01/01/1960' e '31/12/1960'
ordenado pelo nome de forma ascendente.
select
p.cd_paciente as codigo,
p.nm_paciente as nome,
p.dt_nascimento as "Data de Nascimento"
from [Link] p
where
p.Dt_Nascimento BETWEEN '01/01/1960' AND '31/12/1960'
Exemplo 2: Exibir todos os produtos cujo o
código fique entre 100 e 3000.
SELECT
pr.cd_produto as codigo,
pr.ds_produto as "Descrição",
PR.QT_ULTIMA_ENTRADA as Qtde
FROM
[Link] PR
WHERE
pr.cd_produto BETWEEN 100 AND 3000
Sintaxe:
SELECT <lista de colunas>
FROM <tabela>
WHERE <coluna> IS [NOT] NULL
Exemplo 1: Exibir todos os pacientes que não
tenham email, ordenando pelo nome em
ordem descendente.
select
cd_paciente as codigo,
nm_paciente as nome,
p.dt_nascimento as "Data de Nascimento",
[Link]
from [Link] p
where
[Link] is null
order by 2 desc;
Exemplo 2: Exibir todos os pacientes que
tenham email, ordenando pelo nome em
ordem descendente.
select
cd_paciente as codigo,
nm_paciente as nome,
p.dt_nascimento as "Data de Nascimento",
[Link]
from [Link] p
where
[Link] is not null
order by 2 desc;
Sintaxe:
SELECT <lista de colunas>
FROM <tabela>
WHERE <coluna> LIKE <string>
Exemplo 1: Exibir o código e o nome de
todos os pacientes que tenham o nome
começando por “W‟, ordenandos pelo nome.
select
cd_paciente as codigo,
nm_paciente as nome
from
[Link] p
where
nm_paciente like 'W%'
order by 2;
Exemplo 2: Exibir os dados dos pacientes que
tenham o nome terminando por “Silva‟,
ordenados pelo nome.
select
cd_paciente as codigo,
nm_paciente as nome,
from [Link] p
where
nm_paciente like '%SILVA'
order by 2
Exemplo 3: Exibir os dados do paciente que
tenham “GABRIEL‟ em qualquer parte do
nome, ordenados pelo nome.
select
cd_paciente as codigo,
nm_paciente as nome,
from [Link] p
where
nm_paciente like '%GABRIEL%'
order by 2
As funções agregadas:
◦ Operam na coleta de valor em coluna da tabela;
◦ Produzem um resultado único;
◦ Não atua sobre valor nulo.
A cláusula DISTINCT pode ser usada como
parte do argumento para eliminar linhas
repetidas antes de aplicar a função.
Sintaxe:
SELECT COUNT(*)
FROM <tabela>
Exemplo 1: Exibir a quantidade de pacientes
cadastrados.
◦ SELECT COUNT(*) FROM [Link]
Exemplo 2: Exibir a quantidade de pacientes
cadastrados do sexo “F”.
◦ SELECT COUNT(*) FROM [Link] PA
WHERE PA.TP_SEXO = 'F'
Sintaxe:
SELECT SUM(<coluna>)
FROM <tabela>
Exemplo 1: Exibir a soma do custo médio dos
produtos.
SELECT SUM(PR.VL_CUSTO_MEDIO) FROM [Link] PR
Exemplo 2: Exibir o valor total da relação quantidade
x custo médio dos produtos.
SELECT
◦ pr.cd_produto as codigo,
◦ pr.ds_produto as "Descrição",
◦ sum(PR.QT_ULTIMA_ENTRADA * PR.VL_CUSTO_MEDIO ) as Total
◦ FROM
◦ [Link] PR
◦ group by pr.cd_produto,pr.ds_produto
◦ order by 2 desc
Sintaxe:
SELECT AVG(<coluna>)
FROM <tabela>
Exemplo 1: Exibir o valor médio de todos os
produtos.
◦ SELECT
◦ avg( PR.VL_CUSTO_MEDIO ) AS "Custo Médio "
◦ FROM [Link] PR
Exemplo 2: Exibir o preço médio dos
produtos da espécie 1.
◦ SELECT AVG( PR.VL_CUSTO_MEDIO ) AS "CUSTO MÉDIO "
◦ FROM [Link] PR
◦ WHERE pr.cd_especie = 1
Sintaxe:
SELECT MAX(<coluna>)
FROM <tabela>
Exemplo 1: Exibir o maior custo do produto da
espécie 1 da empresa
◦ SELECT
◦ MAX( PR.VL_CUSTO_MEDIO ) AS "Custo Médio "
◦ FROM [Link] PR
WHERE pr.cd_especie = 1
◦ Exemplo 2: Exibir o maior custo do produto da
empresa onde este tenha um teto de R$ 1000,00
◦ SELECT MAX( PR.VL_CUSTO_MEDIO ) AS "Custo Médio "
◦ FROM [Link] PR
◦ WHERE PR.VL_CUSTO_MEDIO <= 1000
Sintaxe:
SELECT MIN(<coluna>)
FROM <tabela>
Exemplo 1: Exibir o menor custo do produto
da espécie 1 da empresa.
◦ SELECT
◦ MIN( PR.VL_CUSTO_MEDIO ) AS "Custo Médio "
◦ FROM [Link] PR
WHERE pr.cd_especie = 2
◦ Exemplo 2: Exibir o menor custo do produto da
empresa onde este tenha um teto de
◦ R$ 5000,00
◦ SELECT MIN( PR.VL_CUSTO_MEDIO ) AS "Custo Médio "
◦ FROM [Link] PR
◦ WHERE PR.VL_CUSTO_MEDIO <= 5000
Sintaxe:
SELECT <lista de colunas>
FROM <tabela>
GROUP BY <tabela>
[HAVING] <condição>
Exemplo 1: Exibir a quantidade de pacientes do sexo
“F”.
◦ select tp_sexo as sexo, count(*)
◦ from [Link] p
◦ where p.tp_sexo = 'F'
◦ group by tp_sexo
Exemplo 2: Exibir a quantidade de pacientes por
bairro.
◦ select
◦ p.nm_bairro,
◦ count(p.cd_paciente)
◦ from [Link] p
◦ group by
◦ p.nm_bairro
Exemplo 5: Exibir a quantidade de pacientes
por bairro onde tem mais de 1000 no bairro.
◦ select
◦ p.nm_bairro,
◦ count(p.cd_paciente)
◦ from [Link] p
◦ group by
◦ p.nm_bairro
◦ having count(p.cd_paciente) >1000
A junção de várias tabelas permite consultar, em um único
SELECT, informações contidas em diferentes tabelas.
Para se fazer uma junção é necessário que as tabelas estejam
relacionadas. (Lembram de PK e FK ?)
A junção entre duas tabelas é realizada através da ligação
entre a chave estrangeira de uma tabela e a respectiva chave
primária referenciada.
Pode-se obter um produto cartesiano entre duas tabelas,
mesmo que elas não estejam relacionadas. Nesse caso, cada
linha de uma tabela será associada a todas as linhas da outra
tabela.
Produto Cartesiano
Pode-se unir várias tabelas em um único SELECT, mas a
ligação é sempre feita entre duas tabelas de cada vez.
Sintaxe:
SELECT <lista de colunas>
FROM <tabela1> [alias1], <tabela2> [alias2]
WHERE <condição de relacionamento>
O formato da condição de relacionamento é:
Exemplo 1: Exibir o código do paciente e o nome e seus
atendimetoa relizados com data, ordenados pelo código do o
paciente e atediemtno.
select
p.cd_paciente,
p.nm_paciente,
a.cd_atendimento,
a.dt_atendimento
from
[Link] a,
[Link] p
where p.cd_paciente = a.cd_paciente
order by 1
A união combina as linhas de duas tabelas em uma
única.
As duas tabelas devem possuir a mesma estrutura:
devem possuir o mesmo número de colunas;
cada par correspondente de colunas deve possuir o
mesmo domínio.
O número de colunas na tabela resultante é o mesmo
das duas tabelas iniciais.
Nenhuma coluna é adicionada.
As linhas repetidas são excluídas do resultado.
O número máximo de linhas é a soma dos números
de linhas das duas tabelas, menos as linhas repetidas.
Sintaxe:
SELECT <lista de colunas>
FROM <tabela1>
UNION [ALL]
SELECT <lista de colunas>
FROM <tabela2>
Uma subconsulta é uma consulta cujo resultado é utilizado
por uma outra consulta mais externa, de forma encadeada e
contida no mesmo comando SELECT.
Uma subconsulta deve estar entre parênteses e é avaliada
apenas uma vez exceto em subconsultas correlacionadas.
Uma subconsulta pode ser:
de valor único: quando retorna um único valor para a
consulta principal; utiliza operadores relacionais =, <>,
>=, =, !>, !<.
de coluna: quando retorna múltiplos valores de uma
coluna para a consulta principal; utiliza o operador IN
ou NOT IN
Subconsulta de Uma Coluna
Sintaxe:
SELECT <lista de colunas>
FROM <tabela>
WHERE <coluna> IN (SELECT ... FROM ...)
Exemplo 1: Exibir código, nome de todos os pacientes do estado da
Paraína e que moram nas codades Mulungo e Pombal.
select
p.cd_paciente, p.nm_paciente
from
[Link] p
where
p.cd_cidade in (
select c.cd_cidade from [Link] c
where c.cd_uf ='PB'
and c.nm_cidade in ('MULUNGU', 'POMBAL') )
Subconsulta de Valor Único
Sintaxe:
SELECT <lista de colunas>
FROM <tabela>
WHERE <coluna> = (SELECT ... FROM ...)
E x e m p l o 1 : E x i b i r o n o me e o v al o r d o p r o d u d o ( s ) d a
especialidade 1 com maior custo médio.
select
p.cd_produto, p.ds_produto, p.vl_custo_medio
from [Link] p
where p.cd_especie = 1
and p.vl_custo_medio = (select max( p1.vl_custo_medio)
from [Link] p1
where p1.cd_especie = 1
)
Usando Subconsulta Correlacionada
Uma subconsulta correlacionada é avaliada através da
seqüência das seguintes etapas:
Etapa: A subconsulta referencia um valor de coluna na
consulta externa, que repassa esse valor à subconsulta;
Etapa: A subconsulta é executada usando o valor repassado
pela consulta externa;
Etapa: A subconsulta retorna um valor à consulta externa,
que será então executada;
Etapa: O processo se repete para cada um dos próximos
registros da consulta externa.
Usando Subconsulta Correlacionada no Select
Exemplo 1: Exibir código, nome e quantidade de
atendimentos de todos os pacientes do estado da Paraína e
que moram nas cidades Mulungo e Pombal.
select
p.cd_paciente, p.nm_paciente,
(select count(*) from [Link] aa
where aa.cd_paciente = p.cd_paciente) as "Qtde Atendimento"
from
[Link] p
where
p.cd_cidade in (
select c.cd_cidade from [Link] c
where c.cd_uf ='PB'
and c.nm_cidade in ('MULUNGU', 'POMBAL') )
O operador IN verifica se um valor existe no resultado
da subconsulta e devolve VERDADEIRO ou FALSO.
O operador EXISTS verifica se a execução da
subconsulta gerou alguma linha como resultado e
devolve VERDADEIRO ou FALSO.
O operador EXISTS só pode ser utilizado para avaliar o
resultado de subconsultas.
O operador EXISTS nunca é precedido por qualquer
coluna ou expressão.
Normalmente as consultas associadas ao operador
EXISTS são correlacionadas.
Exemplo 1: Exibir o código e nome dos pacientes que geraram conta de
internação no ano 2000 por ordem ascendente de nome.
select
p.cd_paciente,
p.nm_paciente,
a.cd_atendimento,
a.dt_atendimento,
trunc(a.dt_atendimento) as dt_atendimento2
from
[Link] a,
[Link] p
where
a.cd_paciente = p.cd_paciente
and a.cd_atendimento in (
select r.cd_atendimento from dbamv.reg_fat r
where to_char(r.dt_inicio, 'yyyy') = '2020'
)
order by 2
Exemplo 2: Exibir o código e nome dos pacientes que
geraram conta de internação no ano 2000 por ordem
ascendente de nome.
select
p.cd_paciente,
p.nm_paciente,
a.cd_atendimento,
a.dt_atendimento,
trunc(a.dt_atendimento) as dt_atendimento2
from
[Link] a,
[Link] p
where
a.cd_paciente = p.cd_paciente
and exists (
select 1 from dbamv.reg_fat r
where to_char(r.dt_inicio, 'yyyy') = '2020'
and r.cd_atendimento = a.cd_atendimento
)
order by 2 asc
A lista de atributos é usada para indicar que campos da
tabela devem ser preenchidos, e com que valores.
Se não for incluída, o BD tentará preencher todos os campos
da tabela na sequência em que foram criados.
Portanto, a lista é obrigatória quando alguns campos não
forem preenchidos, ou quando a ordem dos valores estiver
alterada.
Sintaxe:
INSERT [INTO] <tabela> [(lista de colunas)] VALUES <(lista de
valores)>
Exemplo 1: Criar uma tabela com o nome cidade com o campos
codigo, Nome da Cidade e UG.
INSERT into cidade (codigo, nome, uf)
VALUES (91, 'Muriaé', 'MG')
Treinem um pouco!
Como deve ser feito este mesmo insert sem a declaração dos
campos?
E se eu mudar a ordem dos dados o que é preciso ser feito?
Se uma coluna aceitar valores nulos ou
possuir um valor default, é possível omiti-la
em uma instrução INSERT.
Sempre deverá ser inserido um valor para
uma coluna que seja NOT NULL.
Sintaxe:
INSERT [INTO] <tabela> [(lista de colunas)]
SELECT ... FROM....
Exemplo 1: Cadastrar a cidade de Olinda do estado de
Pernambuco.
INSERT cidade (código, nome, uf)
SELECT x.código, [Link] , [Link] FROM [Link]
A cláusula WHERE é opcional no comando
UPDATE. Se não for informada, a atualização
será realizada em toda a tabela.
◦ Ex: O comando abaixo muda o preço de todas as
fitas cadastradas para 2.20
UPDATE fitas SET preco = 2.20
Sintaxe:
UPDATE <tabela>
SET <coluna> = <expressão>
[WHERE <condição>]
Exemplo 1: Dar um aumento de 12% para os produtos
UPDATE produto
SET venda = venda*1.12
WHERE código IN (2,3)
Exemplo 2: Dar um aumento de 10% para produtos
que tenham seu nome iniciado por “A”, use uma lista.
UPDATE [Link]
SET valor= valor * 1.10
WHERE codigo IN
( SELECT código FROM [Link]
WHERE nome LIKE 'A%'
)
A cláusula WHERE também é opcional no comando
delete. Se não for informada, a deleção será realizada
em toda a tabela.
Sintaxe:
DELETE FROM <tabela> [WHERE <condição>]
Exemplo 1: Excluir todos as cidade com nome iniciado
por 'A'
DELETE FROM [Link]
WHERE NOME LIKE 'A%'
A cláusula WHERE é opcional nos comandos
DELETE/UPDATE. Se não for informada, a
exclusão/alteração será realizada em toda a tabela.
O comando DELETE exclui os dados, mas não exclui a
tabela do BD. Para excluir a tabela inteira (dados e
estrutura), o comando é: DROP TABLE tabela.
◦ Ex: DROP TABLE produto