2010-07-20 21 views
7

Tengo tres tablas con estructura siguiente información: yconsultas SQL para unirse a tres mesas

CREATE TABLE customer (
    customer_id mediumint(8) unsigned NOT NULL auto_increment, 
    name varchar(50) NOT NULL, 
    PRIMARY KEY (customer_id) 
); 

INSERT INTO customer VALUES (1, 'Dagmar'); 
INSERT INTO customer VALUES (2, 'Dietmar'); 
INSERT INTO customer VALUES (3, 'Sabine'); 

CREATE TABLE sales_cars (
    sale_id mediumint(8) unsigned NOT NULL auto_increment, 
    customer_id mediumint(8) unsigned NOT NULL, 
    sale_amount decimal(10,2) NOT NULL, 
    PRIMARY KEY (sale_id) 
); 

INSERT INTO sales_cars VALUES (1, 3, 14.40); 
INSERT INTO sales_cars VALUES (2, 1, 28.30); 
INSERT INTO sales_cars VALUES (3, 2, 34.40); 
INSERT INTO sales_cars VALUES (4, 2, 25.60); 

CREATE TABLE sales_parts (
    sale_id mediumint(8) unsigned NOT NULL auto_increment, 
    customer_id mediumint(8) unsigned NOT NULL, 
    sale_amount decimal(10,2) NOT NULL, 
    PRIMARY KEY (sale_id) 
); 

INSERT INTO sales_parts VALUES (1, 2, 68.20); 
INSERT INTO sales_parts VALUES (2, 3, 21.30); 
INSERT INTO sales_parts VALUES (3, 3, 54.40); 
INSERT INTO sales_parts VALUES (4, 1, 35.70); 

sales_car y sales_parts llevan a cabo ventas realizadas por los clientes. La idea es escribir una consulta que sume el "monto de venta" de los automóviles y las piezas para un cliente en particular y agrupa el resultado por identificación.

¿Alguien tiene alguna sugerencia sobre cómo puedo solucionar este problema?

+2

+1 para incluir la estructura con información de muestra en SQL :) –

Respuesta

2

Algo como esto será lo que está después ...

SELECT *, 
     (SELECT SUM(sale_amount) 
      FROM sales_cars 
      WHERE sales_cars.customer_id = customer.customer_id) AS car_sales, 
     (SELECT SUM(sale_amount) 
      FROM sales_parts 
      WHERE sales_parts.customer_id = customer.customer_id) AS part_sales 
    FROM customer; 
+0

su solución me da la cantidad de venta para cada cliente en las tablas separadas. La idea era obtener un valor único para sale_amount, es decir, agregar los valores de ambas tablas. No he verificado la solución 1 anterior, pero parece ser lo que requiero. Gracias por su contibución – user224645

3

Es posible que desee probar algo como lo siguiente:

SELECT c.customer_id, 
     tot_cars.total + tot_parts.total AS total_sales 
FROM customer c 
JOIN (
      SELECT customer_id, SUM(sale_amount) total 
      FROM  sales_cars 
      GROUP BY customer_id 
     ) tot_cars ON (tot_cars.customer_id = c.customer_id) 
JOIN (
      SELECT customer_id, SUM(sale_amount) total 
      FROM  sales_parts 
      GROUP BY customer_id 
     ) tot_parts ON (tot_parts.customer_id = c.customer_id); 

Resultado:

+-------------+-------------+ 
| customer_id | total_sales | 
+-------------+-------------+ 
|   1 |  64.00 | 
|   2 |  128.20 | 
|   3 |  90.10 | 
+-------------+-------------+ 
3 rows in set (0.03 sec) 

ACTUALIZACIÓN: relación con sus comentarios a continuación:

Vamos a empezar con el campo sale_date:

CREATE TABLE sales_cars (
    sale_id mediumint(8) unsigned NOT NULL auto_increment, 
    customer_id mediumint(8) unsigned NOT NULL, 
    sale_amount decimal(10,2) NOT NULL, 
    sale_date datetime NOT NULL, 
    PRIMARY KEY (sale_id) 
); 

INSERT INTO sales_cars VALUES (1, 3, 14.40, '2010-07-01 12:00:00'); 
INSERT INTO sales_cars VALUES (2, 1, 28.30, '2010-07-05 12:00:00'); 
INSERT INTO sales_cars VALUES (3, 2, 34.40, '2010-07-10 12:00:00'); 
INSERT INTO sales_cars VALUES (4, 2, 25.60, '2010-07-20 12:00:00'); 

para obtener la fecha de la última venta de cada cliente, puede unirse a la consulta descrita anteriormente con otra tabla derivada, de la siguiente manera :

SELECT c.customer_id, 
     tot_cars.total + tot_parts.total AS total_sales, 
     latest_sales.date AS latest_sale 
FROM customer c 
JOIN (
      SELECT customer_id, SUM(sale_amount) total 
      FROM  sales_cars 
      GROUP BY customer_id 
     ) tot_cars ON (tot_cars.customer_id = c.customer_id) 
JOIN (
      SELECT customer_id, SUM(sale_amount) total 
      FROM  sales_parts 
      GROUP BY customer_id 
     ) tot_parts ON (tot_parts.customer_id = c.customer_id) 
JOIN (
      SELECT customer_id, MAX(sale_date) date 
      FROM  sales_cars 
      GROUP BY customer_id 
     ) latest_sales ON (latest_sales.customer_id = c.customer_id); 

Resultado:

+-------------+-------------+---------------------+ 
| customer_id | total_sales | latest_sale   | 
+-------------+-------------+---------------------+ 
|   1 |  64.00 | 2010-07-05 12:00:00 | 
|   2 |  128.20 | 2010-07-20 12:00:00 | 
|   3 |  90.10 | 2010-07-01 12:00:00 | 
+-------------+-------------+---------------------+ 
3 rows in set (0.07 sec) 

¿Ves el patrón? Existen otros enfoques para abordar el mismo problema, pero unirse a tablas derivadas es una técnica muy fácil y directa.

A continuación, en relación con los cambios en la tabla customer, supongo que te refieres algo como esto:

CREATE TABLE customer (
    customer_id mediumint(8) unsigned NOT NULL auto_increment, 
    first_name varchar(50) NOT NULL, 
    last_name varchar(50) NOT NULL, 
    gender char(1) NOT NULL, 
    PRIMARY KEY (customer_id) 
); 

INSERT INTO customer VALUES (1, 'Joe', 'Doe', 'M'); 
INSERT INTO customer VALUES (2, 'Jane', 'Smith', 'F'); 
INSERT INTO customer VALUES (3, 'Peter', 'Brown', 'M'); 

para concatenar los campos de cadena en MySQL, puede simplemente usar la función CONCAT():

SELECT CONCAT(c.first_name, ' ', c.last_name) as full_name 
FROM customer c; 

Devoluciones:

+-------------+ 
| full_name | 
+-------------+ 
| Jane Smith | 
| Peter Brown | 
| Joe Doe  | 
+-------------+ 
3 rows in set (0.01 sec) 

Para aplicar el El señor "o 'señora' condicionalmente, a continuación, puede utilizar el CASE declaración:

SELECT (CASE c.gender WHEN 'M' THEN 'Mr' WHEN 'F' THEN 'Ms' END) salutaiton, 
     CONCAT(c.first_name, ' ', c.last_name) as full_name 
FROM customer c; 

Devuelve:

+------------+-------------+ 
| salutaiton | full_name | 
+------------+-------------+ 
| Ms   | Jane Smith | 
| Mr   | Peter Brown | 
| Mr   | Joe Doe  | 
+------------+-------------+ 
3 rows in set (0.01 sec) 

También puede concatenar los dos campos juntos:

SELECT CONCAT((CASE c.gender WHEN 'M' THEN 'Mr' WHEN 'F' THEN 'Ms' END), ' ', 
       c.first_name, ' ', c.last_name) as full_name 
FROM customer c; 

Devoluciones :

+----------------+ 
| full_name  | 
+----------------+ 
| Ms Jane Smith | 
| Mr Peter Brown | 
| Mr Joe Doe  | 
+----------------+ 
3 rows in set (0.00 sec) 

Por último, se puede adjuntar esto a nuestra consulta principal, de la siguiente manera:

SELECT c.customer_id, 
     CONCAT((CASE c.gender WHEN 'M' THEN 'Mr' WHEN 'F' THEN 'Ms' END), ' ', 
        c.first_name, ' ', c.last_name) as full_name, 
     tot_cars.total + tot_parts.total AS total_sales, 
     latest_sales.date AS latest_sale 
FROM customer c 
JOIN (
      SELECT customer_id, SUM(sale_amount) total 
      FROM  sales_cars 
      GROUP BY customer_id 
     ) tot_cars ON (tot_cars.customer_id = c.customer_id) 
JOIN (
      SELECT customer_id, SUM(sale_amount) total 
      FROM  sales_parts 
      GROUP BY customer_id 
     ) tot_parts ON (tot_parts.customer_id = c.customer_id) 
JOIN (
      SELECT customer_id, MAX(sale_date) date 
      FROM  sales_cars 
      GROUP BY customer_id 
     ) latest_sales ON (latest_sales.customer_id = c.customer_id); 

Devuelve:

+-------------+----------------+-------------+---------------------+ 
| customer_id | full_name  | total_sales | latest_sale   | 
+-------------+----------------+-------------+---------------------+ 
|   1 | Mr Joe Doe  |  64.00 | 2010-07-05 12:00:00 | 
|   2 | Ms Jane Smith |  128.20 | 2010-07-20 12:00:00 | 
|   3 | Mr Peter Brown |  90.10 | 2010-07-01 12:00:00 | 
+-------------+----------------+-------------+---------------------+ 
3 rows in set (0.02 sec) 
+0

esto es exactamente lo que quería gracias. Imagine que ahora borro la columna de nombre en la tabla de clientes para agregar 3 nuevas columnas: "género", "apellido" y "primer nombre". La idea es que se muestre el total de ventas con el nombre del cliente en la forma del Sr. Dietmar Peter, por ejemplo. Entonces, la complicación aquí es convertir el género en Mr of Mrs y combinar first y lastname. En segundo lugar, si se añadiera una nueva columna "fecha_venta" a sales_cars y sales_parts, ¿cómo generaría la fecha de la venta más reciente junto con total_sales en una nueva columna? Muchas gracias – user224645

+0

@vibanty: compruebe la respuesta actualizada :) –

1
select customer.customer_id,(totalcar + totalparts) as total from customer 
inner join 
(select customer_id ,sum(sale_amount) as totalcar 
     from sales_cars group by customer_id) d 
on customer_id = d.customer_id 
inner join 
(select customer_id , sum(sale_amount) as totalparts 
     from sales_parts group by customer_id) d1 

on customer_id = d1. customer_id 
+0

He verificado su resultado y los siguientes puntos son para tener en cuenta: 1- customer_id después de la parte "on" de la unión es ambiguos ya que customer_id aparece en las tres tablas 2 - su solución emitirá un aparte para los autos y las ventas de partes de cada cliente. El requisito es sumar la suma. Vea la primera solución que he verificado que es correcta. Gracias por su contribución – user224645

+0

vea la respuesta que se actualizó ahora –

0

no pienso subconsultas agregados es buena idea

select customer_id, sum(sale_amount) from (
select customer.customer_id, sale_amount from customer 
join sales_cars on sales_cars.customer_id = customer.customer_id 
union all 
select customer.customer_id, sale_amount from customer 
join sales_parts on sales_parts.customer_id = customer.customer_id 
) totals group by customer_id 
+3

Cuando se atrape, escriba 'UNION' y compruebe si' UNION ALL' funcionará, ya que el delta de rendimiento es ~ O (n log n). En realidad, aquí 'UNION' sin' ALL' es un error (aunque generalmente no tendrá una parte que cueste exactamente lo mismo que un automóvil completo vendido al mismo cliente). – Unreason

+0

De acuerdo, aquí falta la clave sintética o la unión. –

+0

muchas gracias por su contribución.Imagine que ahora borro la columna de nombre en la tabla de clientes para agregar 3 nuevas columnas: "género", "apellido" y "primer nombre". La idea es que se muestre el total de ventas con el nombre del cliente en la forma del Sr. Dietmar Peter, por ejemplo. Entonces, la complicación aquí es convertir el género en Mr of Mrs y combinar first y lastname. En segundo lugar, si se añadiera una nueva columna "fecha_venta" a sales_cars y sales_parts, ¿cómo generaría la fecha de la venta más reciente junto con total_sales en una nueva columna? Muchas gracias – user224645