Você conhece a participação lateral no SQL?

Introdução Você já ficou preso tentando escrever uma consulta SQL que precisa executar um subclulação para cada linha da sua tabela principal? Talvez você precisasse encontrar as três últimas postagens do blog para todos os usuários ou os 5 principais produtos para cada categoria. Esses problemas no estilo “for-ECO” podem levar a consultas complicadas, lentas e difíceis de ler. Este é o problema exato em que a junção lateral foi projetada para resolver. O que realmente significa lateral? Primeiro, vamos esclarecer um ponto crítico. Embora seja comum ouvir “Junção lateral”, o verdadeiro poder vem da própria palavra -chave lateral. Não é um tipo de junção como interno ou esquerdo; É um modificador que altera fundamentalmente a forma como uma subconsulta na cláusula do From se comporta. Pense em “lateral” como significado “de lado”. Uma subconeração padrão em uma cláusula da cláusula é executada isoladamente e não pode fazer referência a outras tabelas na mesma cláusula. A palavra -chave lateral quebra esta regra. Ele fornece uma permissão de subconsência para olhar de lado para as colunas de tabelas que aparecem antes dela na lista de From. Isso permite um poderoso padrão de loop for-ECH diretamente no seu SQL. Um problema de negócios do mundo real (PostgreSQL), vamos criar um cenário de comércio eletrônico com clientes, produtos e pedidos para demonstrar junções laterais em ação usando o PostgreSQL. Criar clientes da tabela (Customer_id int Primary Key, Customer_name Varchar (100)); Crie pedidos de tabela (Order_id int Primary Key, Customer_id Int, Order_date Data, Montante Int, Itens JSONB, – Para armazenar uma lista de produtos nas tags do pedido Varchar[] – para armazenar tags como ‘presente’, ‘rush_delivery’); – Semear as tabelas com dados versáteis de dados em clientes (Customer_Id, Customer_Name) (1, ‘Alice’), (2, ‘Bob’), (3, ‘Charlie’); Inserir em pedidos (order_id, customer_id, order_date, quantidade, itens, tags) valores (101, 1, ‘2025-01-15’, 25, ‘[{“product”: “Mouse”, “price”: 25.00}]’,’ {“Sale”} ‘), (102, 1,’ 2025-06-20 ‘, 120,'[{“product”: “Webcam”, “price”: 45.00}, {“product”: “Keyboard”, “price”: 75.00}]’,’ {“trabalho”, “rush_delivery”} ‘), (103, 1,’ 2025-07-01 ‘, 15,'[{“product”: “Mousepad”, “price”: 15.00}]’,’ {} ‘), (104, 2,’ 2025-02-25 ‘, 250,'[{“product”: “Monitor”, “price”: 250.00}]’,’ {} ‘), (105, 2,’ 2025-07-10 ‘, 80,'[{“product”: “Keyboard”, “price”: 80.00}]’,’ {“urgent”} ‘), (106, 3,’ 2025-04-05 ‘, 120,'[{“product”: “Headphones”, “price”: 120.00}]’,’ {“presente”, “rush_delivery”} ‘); Digite o modo de saída de tela cheia de tela cheia nos casos de uso lateral. Portanto, vamos resolver alguns desafios: 1- Selecionando as principais linhas por meta do grupo: encontre os dois pedidos mais recentes para cada cliente. Quando você encontra esse problema, pode pensar em algumas opções disponíveis. Vamos examinar cada opção e, finalmente, usaremos a opção lateral. Opção 1: A abordagem da função da janela Esta é uma maneira comum de resolver problemas de N. Com os Rankedorders como ( – Etapa 1: digitalize todos os pedidos e atribua uma classificação a cada um dentro de seu grupo de clientes selecione C.Customer_Name, O.Order_Date, O.Items, Row_Number () sobre (Partição de C.Customer_id Ordem por O.Order_Date Desc) como RN de Customers c JONE OS ON C.CUSTOMER_ Para aqueles que você deseja selecionar Customer_name, Order_date, itens de Rankedorders onde RN <= 2;

Enter fullscreen mode

Exit fullscreen mode

Why it’s less ideal: While it works perfectly, the logic is indirect. You have to create a temporary ranked dataset of all orders and then query it again.

Option 2: The Correlated Subquery Approach

A traditional correlated subquery is often used to fetch a single piece of related data.

— This only works for a single value, not a full row.
SELECT
c.customer_name,
(SELECT o.order_date FROM orders o WHERE o.customer_id = c.customer_id ORDER BY o.order_date DESC LIMIT 1) AS latest_order_date
FROM
customers c;

Enter fullscreen mode

Exit fullscreen mode

Why it fails for this problem: The fundamental limitation of a scalar subquery (one used in a SELECT list) is that it must return exactly one column and one row. It’s physically impossible to use this technique to fetch the two full order records (with multiple columns like order_date and items) that our problem requires. It’s the wrong tool for the job.

Option 3: The GROUP BY Approach

GROUP BY is built for aggregation, not for retrieving individual rows from a group.

— This finds the latest date, but loses all other details of that order.
SELECT
c.customer_name,
MAX(o.order_date) AS latest_order_date
FROM
customers c
JOIN
orders o ON c.customer_id = o.customer_id
GROUP BY
c.customer_name;

Enter fullscreen mode

Exit fullscreen mode

Why it fails for this problem: The entire purpose of GROUP BY is to collapse many rows into a single summary row. It can give you the latest date, the total count, or the average amount, but it discards the individual rows in the process. You cannot use it to select the “top 2” original rows from the group.

Option 4: The LATERAL Solution

SELECT
c.customer_name,
recent_orders.order_date,
recent_orders.items
FROM
customers c
LEFT JOIN LATERAL (
SELECT
o.order_date,
o.items
FROM
orders o
WHERE
o.customer_id = c.customer_id
ORDER BY
o.order_date DESC
LIMIT 2
) AS recent_orders ON true;

Enter fullscreen mode

Exit fullscreen mode

As you see, it reads like a direct translation of our request: “For each customer, get their two most recent orders.”

Tip: The ON TRUE clause is used since we’re not joining on specific columns but including the subquery’s results.

But why is it better than the Window Function approach? The LATERAL approach feels more natural because it integrates the filtering (LIMIT 2) directly into the “for-each-customer” step, avoiding the separate ranking-then-filtering process.

Result:

customer_name
order_date
items

Alice
2025-07-01
[{“product”: “Mousepad”, “price”: 15.00}]

Alice
2025-06-20
[{“product”: “Webcam”, “price”: 45.00}, {“product”: “Keyboard”, “price”: 75.00}]

Bob
2025-07-10
[{“product”: “Keyboard”, “price”: 80.00}]

Bob
2025-02-25
[{“product”: “Monitor”, “price”: 250.00}]

Charlie
2025-04-05
[{“product”: “Headphones”, “price”: 120.00}]

2- Unpacking JSONB Order Details

Goal: Find all customers who have ever ordered a ‘Keyboard’.

SELECT DISTINCT — Use DISTINCT to only list each customer once
c.customer_name
FROM
orders o
JOIN
customers c ON o.customer_id = c.customer_id
— For each order ‘o’, expand its items into a table called ‘item_details’
JOIN LATERAL jsonb_to_recordset(o.items) AS item_details(product TEXT, price DECIMAL) ON true
WHERE
item_details.product=”Keyboard”;

Enter fullscreen mode

Exit fullscreen mode

The function jsonb_to_recordset turns a JSON array into a virtual table. LATERAL lets us run this function for every single order row.

Result:

3- Searching Array Data With UNNEST

Goal: Find the names and order dates for all orders tagged with ‘rush_delivery’.

SELECT
c.customer_name,
o.order_date,
tag_value
FROM
orders o
JOIN
customers c ON o.customer_id = c.customer_id
— For each order ‘o’, expand its tags array into a single-column table
, LATERAL unnest(o.tags) AS tag_value
WHERE
tag_value=”rush_delivery”;

Enter fullscreen mode

Exit fullscreen mode

The unnest function expands an array into a set of rows. LATERAL lets us do this for each order’s tags array.

However, PostgreSQL allows you to omit LATERAL in some cases implicitly. When you use a set-returning function like unnest() in the FROM clause with a table column as argument (e.g., o.tags), PostgreSQL treats it as a LATERAL join implicitly. So, in this case you can remove LATERAL and the query will work; but it is best practice to keep

Tip: Keep in mind that the , is a shorthand for CORSS JOIN; which means it should be CROSS JOIN LATERAL.

Result:

customer_name
order_date
tag_value

Alice
2025-06-20
rush_delivery

Charlie
2025-04-05
rush_delivery

4- Using Functions and Calculations per Row

Goal: Apply a 10% discount if the order amount exceeds 100.

SELECT
c.customer_name,
o.amount,
d.discount
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
CROSS JOIN LATERAL (
SELECT CASE
WHEN o.amount > 100 então o.amount * 0.1 else 0 final como desconto) d; Digite o modo de tela cheia de saída Modo de tela cheia Resultado: Customer_name Desconto Alice 25 0 Alice 120 12 Alice 15 0 BOB 250 25 BOB 80 0 Charlie 120 12 Junção lateral vs. sublocinato correlacionado correlacionou sublocinatos e junções laterais no SQL permitem uma subconsência para referência a colunas de uma tabela anterior; No entanto, eles diferem em suas capacidades. Subconsclarias correlacionadas: uma subconsulta correlacionada tradicional deve retornar um único valor escalar (uma coluna, uma linha) para cada linha processada pela consulta externa. Eles geralmente são encontrados na lista de seleção, onde a cláusula ou a cláusula. Ele é executado repetidamente para cada linha, o que pode levar à digitalização da tabela de destino várias vezes. Junho lateral: uma junção lateral pode retornar várias colunas e várias linhas da subconsência para cada linha da consulta externa. É colocado na cláusula de From, atuando como uma junção entre a tabela externa e o resultado da subconsência lateral. Permite que o PostgreSQL planeje a execução da subconeração com mais eficiência, potencialmente reduzindo as varreduras de tabela. Quando evitar laterais? Um especialista sabe quando não usar uma ferramenta. Lateral é uma solução especializada, e usá -la para problemas mais simples é ineficiente e excessivamente complexa. Vamos apresentar alguns casos de uso. Caso 1: Para o problema “Top-1”, use distinto se você precisar apenas do único registro mais recente, distinto é construído para propósitos, mais declarativo e muitas vezes mais rápido. – Melhor maneira de obter apenas a única ordem mais recente selecionar distinto em (c.customer_id) c.customer_name, o.order_date dos clientes c ingressar em pedidos o em c.customer_id = o.customer_id Ordem por c.customer_id, o.order_date desc; Digite o modo de saída do modo de tela cheia por que é melhor: o distinto é a solução idiomática do PostGresql para o problema “Top-1”. Sua intenção é mais clara e o planejador de consultas pode otimizá -lo com mais eficiência. Caso 2: Para agregados simples, use o grupo por se você precisar apenas de um cálculo de resumo (contagem, soma, avg) e não os detalhes das linhas individuais, o grupo por é a ferramenta padrão correta. – Obtenha o número total de pedidos para cada cliente Selecione C.Customer_Name, Count (O.Order_Id) como total_orders dos clientes C Participe de Ordens O em c.customer_id = o.customer_id Group por c.customer_name; Digite o modo de saída do modo de tela cheia por que é melhor: essa é a maneira mais fundamental e eficiente de executar agregações. Usar lateral para contar linhas seria um anti-padrão complicado. Considerações de desempenho lateral pode melhorar o desempenho em relação às subconsivas correlacionadas, porque o planejador de consultas do PostgreSQL pode otimizá -las melhor. No entanto: Uso do índice: Verifique se existem índices em condições de união (por exemplo, cliente_id na tabela de pedidos). Volume de dados: para grandes conjuntos de dados, teste de teste para evitar execuções excessivas de subconsência. Complexidade da consulta: as subconesas laterais complexas ainda podem ter muito recursos se não forem otimizados. Dica: use Explique para analisar o plano de consulta e garantir que os índices sejam usados de maneira eficaz. Criar índice IDX_ORDERS_CUSTOMER_ID ON ORDERS (Customer_id); Digite a conclusão lateral do modo de tela cheia do modo de tela cheia. Desde a extração de dados do JSONB até a seleção de Nas principais linhas por grupo, elas oferecem flexibilidade que não falam flexibilidade e subcons do tradicional. Ao entender quando usar junções laterais, otimizando o desempenho com índices e evitando o uso excessivo em cenários simples, você pode desbloquear todo o seu potencial. Tente experimentar lateral no seu próximo projeto PostGresql e veja como ele simplifica seus desafios de dados! Se você estiver interessado em explorar mais, confira esses artigos.

Fonte

Publicar comentário

Você pode ter perdido