2016-06-02 1 views
3

J'ai une requête comme ceci:Postgres voir avec requête SQL imbriquées ou comment trouver la dernière INET

SELECT DISTINCT(orders.email), uuid_nil() AS customer_id, 'Order' AS customer_type, orders.first_name, orders.last_name, MAX(orders.paid_at) AS last_order_at, 1 AS order_count, SUM(orders.total_price_cents) AS total_spent_pennies 
FROM orders 
WHERE orders.state = 'paid' AND orders.customer_id IS null 
GROUP BY orders.email, customer_id, orders.first_name, orders.last_name 
UNION 
SELECT DISTINCT(customers.email), customers.id AS customer_id, 'Customer' AS customer_type, customers.first_name, customers.last_name, MAX(orders.paid_at) AS last_order_at, COUNT(orders.*) AS order_count, SUM(orders.total_price_cents) AS total_spent_pennies 
FROM customers 
JOIN orders ON customers.id = orders.customer_id 
GROUP BY customers.email, customers.id, customers.first_name, customers.last_name 

qui ressemble à:

+-------------------------------+--------------------------------------+---------------+------------+--------------+-------------------------+-------------+---------------------+ 
| email       | customer_id       | customer_type | first_name | last_name | last_order_at   | order_count | total_spent_pennies | 
+-------------------------------+--------------------------------------+---------------+------------+--------------+-------------------------+-------------+---------------------+ 
| [email protected]    | 00000000-0000-0000-0000-000000000000 | Order   | Richard | Doe   | 2015-12-18 14:45:22 UTC | 1   | 2000    | 
| [email protected]     | 00000000-0000-0000-0000-000000000000 | Order   | Paul  | Doe   | 2016-04-05 09:04:57 UTC | 1   | 5000    | 
+-------------------------------+--------------------------------------+---------------+------------+--------------+-------------------------+-------------+---------------------+ 

Ma question est de savoir comment puis-je inclure leur dernier Adresse IP également (colonne INET). Une date, je peux simplement utiliser la fonction d'agrégat MAX mais l'adresse IP n'en a évidemment pas.

Fondamentalement, comment puis-je combiner cette requête ci-dessus pour me donner une nouvelle colonne avec leur adresse last_ip avec quelque chose comme:

SELECT browser_ip FROM orders 
WHERE email = '[email protected]' 
ORDER BY paid_at DESC 
LIMIT 1 

Répondre

1

Vous pouvez probablement vous en passer avec une sous-requête simple comme celle-ci, il vous suffit de nommer vos requêtes pour pouvoir faire référence entre elles.

http://www.techonthenet.com/postgresql/subqueries.php

Par exemple, la première partie de votre requête serait quelque chose comme:

SELECT DISTINCT(c1.email), c1.id AS customer_id, 'Customer' AS customer_type, 
c1.first_name, c1.last_name, MAX(orders.paid_at) AS last_order_at, 
COUNT(orders.*) AS order_count, SUM(orders.total_price_cents) AS total_spent_pennies, 
(SELECT browser_ip FROM orders WHERE c1.email = orders.email 
ORDER BY paid_at DESC LIMIT 1) last_ip 
FROM customers c1 
JOIN orders ON c1.id = orders.customer_id 
GROUP BY c1.email, c1.id, c1.first_name, c1.last_name 
0

Cast to varchar, et utiliser string_agg - quelque chose comme:

SELECT email, paid_at, string_agg(browser_ip::varchar, ',') as ips 
WHERE email = '[email protected]' 
GROUP BY email, paid_at 
ORDER BY email, paid_at DESC 
LIMIT 1 

devrait fonctionne très bien.

0

A couple d'options:

  1. Utilisez une sous-requête LATERAL. Notez que cela forcera une jointure de boucle imbriquée.
  2. Ecrivez une fonction pour récupérer la dernière adresse IP et l'appeler. Cela forcera également une boucle imbriquée.
  3. Utilisez une fonction de fenêtre et un filtre sur cela. Cela est généralement pire car vous devez scanner toute la table avant de rejoindre.

Dans votre cas, à cause de l'union, je ferais probablement la deuxième et faire quelque chose comme ceci:

CREATE OR REPLACE FUNCTION latest_ip(in_email text) 
RETURNS inet LANGUAGE SQL AS 
$$ 
SELECT paid_at, string_agg(browser_ip::varchar, ',') as ips 
WHERE email = in_email 
GROUP BY paid_at 
ORDER BY paid_at DESC 
LIMIT 1 
$$; 

alors vous suffit d'appeler latest_ip(orders.email) dans votre liste de colonnes

L'autre il faudrait dupliquer ce qui précède en tant que sous-requête à la suite d'une déclaration LATÉRALE sur les deux branches de votre syndicat. Il vaut la peine de le savoir, mais peut être un problème de maintenance dans ce cas.