SQL nas Linguagens
O SQL que você aprendeu é a língua do banco. Mas um site ou um aplicativo não é feito só de SQL: ele é feito numa linguagem de programação — Python, PHP, JavaScript, Java, C# — e essa linguagem fala com o banco para pedir e gravar dados. A boa notícia é que o SQL é quase o mesmo em todas; o que muda é só a "cola" em volta: como conectar, como mandar a consulta e como ler o resultado. Nesta aula você vê a mesma consulta na Loja Aurora saindo de cinco linguagens, e descobre que o passo a passo é sempre o mesmo.
- O que é um driver (a biblioteca que liga a linguagem ao banco).
- O fio condutor comum: conectar → preparar o SQL → ligar os parâmetros → ler as linhas → fechar.
- A mesma consulta em Python, PHP, Node, Java e C#.
- A marca de espaço reservado de cada uma (
?,:nome,$1…). - Por onde começar em cada linguagem, com os guias de PHP, Java, C# e C.
Só o exemplo em Python roda aqui dentro (na máquina da Ana); os outros são ilustrativos, para você ver a forma. Todos usam parâmetros (aula Consultas com Parâmetros): nunca cole dados no SQL à mão, em linguagem nenhuma.
A ideia: o banco e o tradutor
O banco de dados é como um almoxarife que só entende SQL. A sua linguagem de programação é outra pessoa, que fala outra língua. Entre as duas fica um tradutor: uma biblioteca que recebe o SQL do seu programa, entrega ao banco e traz a resposta de volta num formato que o seu programa entende (uma lista, um objeto). Esse tradutor tem nome: é o driver (ou "conector") do banco.
Cada linguagem tem o seu driver para o SQLite (e outros para o MySQL, o PostgreSQL…). Troque o banco e você troca o driver; o seu SQL continua quase igual. É por isso que aprender SQL vale para qualquer linguagem.
O fio condutor (igual em todas)
Não importa a linguagem, rodar uma consulta tem sempre os mesmos passos:
- Conectar ao banco (abrir o arquivo
loja.db, ou ligar no servidor). - Preparar o SQL, com espaços reservados no lugar dos valores.
- Ligar os valores aos espaços reservados (o bind).
- Executar e ler as linhas que voltaram.
- Fechar a conexão no fim.
A consulta que vamos usar em todas é a mesma: os produtos mais baratos que um certo preço. Em SQL puro, no editor, ela é esta (aqui com o preço 5 já no lugar):
SELECT nome, preco FROM produtos WHERE preco < 5 ORDER BY preco;
Nos programas, o 5 vira um parâmetro. Vamos ver linguagem por linguagem.
1. Python — módulo sqlite3
O Python já vem com o driver do SQLite embutido: o módulo sqlite3. É o único exemplo que roda aqui de verdade, na máquina da Ana:
import sqlite3
con = sqlite3.connect("loja.db") # 1. conectar
con.row_factory = sqlite3.Row # ler colunas pelo nome
sql = "SELECT nome, preco FROM produtos WHERE preco < ? ORDER BY preco LIMIT 3"
for p in con.execute(sql, (5,)): # 2-4. preparar, ligar o 5, ler
print(f"{p['nome']:<28} R$ {p['preco']:.2f}")
con.close() # 5. fechar
$ python3 lista.py Lápis Grafite HB R$ 1.15 Caneta Esferográfica Azul R$ 2.79 Marca-texto Amarelo R$ 4.90
- sqlite3.connect("loja.db")
- Abre (ou cria) o arquivo do banco e devolve a conexão.
- WHERE preco < ?
- O espaço reservado posicional (aula Consultas com Parâmetros).
- con.execute(sql, (5,))
- Prepara, liga o
5ao?, executa e devolve as linhas, que oforpercorre. - con.close()
- Fecha a conexão. Sempre feche, ou use um
with.
2. PHP — PDO
No PHP, o jeito moderno é o PDO (PHP Data Objects), um driver único que fala com SQLite, MySQL, PostgreSQL e outros trocando só o começo da conexão (o DSN). O espaço reservado é o mesmo ? (ou o :nome):
<?php
$pdo = new PDO("sqlite:loja.db"); // 1. conectar
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "SELECT nome, preco FROM produtos WHERE preco < ? ORDER BY preco LIMIT 3";
$stmt = $pdo->prepare($sql); // 2. preparar
$stmt->execute([5]); // 3-4. ligar o 5 e executar
foreach ($stmt as $p) { // ler as linhas
printf("%-28s R$ %.2f\n", $p["nome"], $p["preco"]);
}
(Ilustrativo: não roda no editor.) O prepare cria o comando preparado e o execute([5]) liga o valor ao ?. Para começar em PHP, veja o Guia PHP do mesmo autor: Conectar com PDO e Prepared Statements e SQL Injection.
3. Node.js — node:sqlite
O Node.js ganhou um driver de SQLite embutido, o módulo node:sqlite, a partir do Node 22.5 (ainda marcado como experimental). A forma lembra a dos outros: preparar e ligar o valor.
import { DatabaseSync } from "node:sqlite";
const db = new DatabaseSync("loja.db"); // 1. conectar
const stmt = db.prepare( // 2. preparar
"SELECT nome, preco FROM produtos WHERE preco < ? ORDER BY preco LIMIT 3"
);
for (const p of stmt.all(5)) { // 3-4. ligar o 5, ler
console.log(p.nome, p.preco);
}
db.close(); // 5. fechar
O node:sqlite só existe do Node 22.5 em diante. Em versões anteriores (como o Node 20), ele não está presente: require("node:sqlite") dá o erro ERR_UNKNOWN_BUILTIN_MODULE. Nesses casos, o costume é instalar um pacote da comunidade, como o better-sqlite3, que tem uma forma muito parecida. Por isso este exemplo fica ilustrativo.
4. Java — JDBC
Em Java, o padrão para falar com bancos é o JDBC (Java Database Connectivity). Você usa um PreparedStatement, liga os valores por posição (começando em 1, não em 0) e lê um ResultSet:
import java.sql.*;
public class Lista {
public static void main(String[] args) throws SQLException {
String url = "jdbc:sqlite:loja.db"; // 1. conectar
String sql = "SELECT nome, preco FROM produtos WHERE preco < ? ORDER BY preco LIMIT 3";
try (Connection con = DriverManager.getConnection(url);
PreparedStatement ps = con.prepareStatement(sql)) { // 2. preparar
ps.setDouble(1, 5); // 3. ligar o 5 (posição 1)
try (ResultSet rs = ps.executeQuery()) { // 4. executar e ler
while (rs.next()) {
System.out.printf("%-28s R$ %.2f%n",
rs.getString("nome"), rs.getDouble("preco"));
}
}
} // 5. o try fecha tudo
}
}
(Ilustrativo.) O try (…) com os recursos entre parênteses fecha a conexão sozinho no fim. Para começar em Java, veja o Guia Java do mesmo autor.
5. C# — ADO.NET (Microsoft.Data.Sqlite)
No C# (.NET), o padrão é o ADO.NET. Com o pacote Microsoft.Data.Sqlite, você cria um comando, adiciona os parâmetros (aqui nomeados, com $) e lê com um DataReader:
using Microsoft.Data.Sqlite;
using var con = new SqliteConnection("Data Source=loja.db"); // 1. conectar
con.Open();
var cmd = con.CreateCommand(); // 2. preparar
cmd.CommandText = "SELECT nome, preco FROM produtos WHERE preco < $preco ORDER BY preco LIMIT 3";
cmd.Parameters.AddWithValue("$preco", 5); // 3. ligar o 5
using var reader = cmd.ExecuteReader(); // 4. executar e ler
while (reader.Read())
{
Console.WriteLine($"{reader.GetString(0),-28} R$ {reader.GetDouble(1):F2}");
}
(Ilustrativo.) O $preco é um espaço reservado nomeado (o SQLite aceita :nome, @nome e $nome). Para começar em C#, veja o Guia C# do mesmo autor.
O SQLite é escrito em C, e dá para usá-lo direto, sem driver, com funções como sqlite3_open, sqlite3_prepare_v2, sqlite3_bind_* e sqlite3_step. É mais trabalhoso (é a "cozinha" que as outras linguagens escondem), mas é a base de todas elas. O Guia C do mesmo autor ajuda com a linguagem.
Lado a lado
| Linguagem | Driver / biblioteca | Conectar (SQLite) | Espaço reservado |
|---|---|---|---|
| Python | sqlite3 (embutido) | sqlite3.connect("loja.db") | ? e :nome |
| PHP | PDO | new PDO("sqlite:loja.db") | ? e :nome |
| Node.js | node:sqlite (Node 22.5+) | new DatabaseSync("loja.db") | ? e :nome |
| Java | JDBC | jdbc:sqlite:loja.db | ? (posição começa em 1) |
| C# | ADO.NET (Microsoft.Data.Sqlite) | "Data Source=loja.db" | $nome, :nome, @nome |
Repare: fora o nome das funções, o SQL é idêntico e o passo a passo é o mesmo. Quem aprende SQL aprende a parte que não muda.
Para MySQL, PostgreSQL e SQL Server, você troca o driver e o endereço da conexão (servidor, usuário, senha), mas o SQL e os passos continuam. O PostgreSQL usa a marca $1, $2 nos parâmetros; o MySQL e o SQL Server usam ? ou nomes, conforme o driver. Nesses bancos entram também os usuários e permissões: o programa conecta com um usuário que só pode o necessário.
Quando dá errado
Escreva o nome da tabela errado — produto em vez de produtos — e o banco devolve sempre a mesma mensagem crua. Veja no editor:
SELECT * FROM produto;
A mensagem do SQLite é no such table: produto ("não existe a tabela produto"). Num programa, essa mesma mensagem chega dentro de um erro da linguagem. Em Python, por exemplo:
$ python3 -c "import sqlite3; sqlite3.connect('loja.db').execute('SELECT * FROM produto')"
Traceback (most recent call last):
File "<string>", line 1, in <module>
import sqlite3; sqlite3.connect('loja.db').execute('SELECT * FROM produto')
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
sqlite3.OperationalError: no such table: produto
Em PHP seria uma PDOException, em Java uma SQLException, em C# uma SqliteException — mas o texto do banco, no such table: produto, é o mesmo em todas. Por isso vale aprender a ler as mensagens do SQLite: elas aparecem igual em qualquer linguagem.
Em qualquer dessas linguagens, montar o SQL juntando texto ("… WHERE nome = '" + digitado + "'") reabre a porta do SQL Injection e quebra com nomes que têm apóstrofo, como Loja D'Água. A regra vale para todas: valor vindo de fora entra por parâmetro, nunca colado.
Referência rápida
| Passo | O que é |
|---|---|
| Driver | A biblioteca que liga a linguagem ao banco. |
| Conectar | Abrir o arquivo (SQLite) ou ligar no servidor. |
| Preparar | Montar o SQL com espaços reservados. |
| Ligar (bind) | Encaixar os valores nos espaços reservados. |
| Ler | Percorrer as linhas devolvidas. |
| Fechar | Encerrar a conexão no fim. |
Exercícios
1. O que é um "driver" de banco de dados?
2. Trocando de linguagem (de Python para Java, por exemplo), o que mais muda?
3. Em todas as linguagens desta aula, como o valor de busca deve entrar na consulta?
Experimente: a consulta que todas rodam
Missão: escreva, em SQL puro, a consulta que todos os programas rodaram: os produtos com preco menor que 5, ordenados por preco. (É o que sai quando o parâmetro recebe o valor 5.) Devem vir 3 produtos.
SELECT nome, preco FROM produtos;
SELECT nome, preco FROM produtos WHERE preco < 5 ORDER BY preco;
Missão final
Missão: provoque, de propósito, o erro que todas as linguagens embrulham. Troque a consulta para ler de uma tabela que não existe (por exemplo, cliente, no singular) e veja a mensagem do SQLite. (Esta caixa espera um erro.)
SELECT * FROM clientes LIMIT 1;
SELECT * FROM cliente LIMIT 1;
Resumo
- Um programa fala com o banco por um driver: a biblioteca que traduz entre a linguagem e o SQL.
- O passo a passo é sempre o mesmo: conectar → preparar → ligar os parâmetros → ler → fechar.
- O SQL quase não muda de uma linguagem para outra; muda a "cola" em volta e a marca de espaço reservado (
?,:nome,$1…). - Em todas, os valores entram por parâmetro (aula Consultas com Parâmetros), nunca colados — senão volta o SQL Injection.
- O erro do banco (como
no such table) é o mesmo texto em qualquer linguagem, só embrulhado num erro diferente. - Para aprofundar em cada linguagem: os guias de PHP, Java, C# e C do mesmo autor.