sql: suma de columnas por ID distinto y grupo por columna diferente

CorePress2024-01-24  11

Digamos que tengo la siguiente tabla:

create table orders (id int, order_id int, vendor varchar, price int);

INSERT INTO orders values 
(1, 1, 'nike', 10),
(2, 2, 'nike', 10),
(3, 3, 'adidas', 15),
(4, 3, 'adidas', 15);

Quiero obtener la suma del precio por order_id distinto y agrupado por proveedor. Entonces la respuesta aquí sería:

| vendor | sum |
|  nike  | 20  |
| adidas | 15  |

La razón por la que adidas tiene 15 es porque solo tomamos uno de los precios ya que el otro registro de adidas tiene el mismo order_id. ¿También es posible hacer esto sin una consulta anidada?

¿Qué pasa si hay otra fila (5, 3, 'adidas', 25)? El precio es diferente. ¿Cuál sería la suma?

-forpas

27/03/2021 a las 16:24

@forpas Es mi escenario, ese nunca sería el caso.

-camiseta

27/03/2021 a las 17:45



------------------------------------

En Postgres, usaría distintivo con grupo por:

select vendor, sum(price)
from (select distinct on (order_id, vendor) o.*
      from orders o
      order by order_id, vendor
     ) o
group by vendor;

Nota: Si los precios son diferentes dentro de un pedido determinado, se elige un precio arbitrario.

Sugiero esto porque distinguir suele ser el método más rápido para reducir datos en este tipo de fashion.

0



------------------------------------

La consulta en dos partes es bastante sencilla. Primero obteniendo los distintos órdenes, luego haciendo la suma:

WITH distinct_orders AS (
    SELECT vendor, order_id, min(price) as price
    FROM orders
    GROUP BY vendor, order_id
)
SELECT vendor, sum(price)
FROM distinct_orders
GROUP BY vendor;

Si es realmente importante para usted hacer esto con una sola selección, puede utilizar una autounión, pero tenga en cuenta que en realidad esta no es una mejor solución:

SELECT o.vendor, sum(o.price)
FROM orders o
LEFT JOIN orders o1 
  ON (o.vendor = o1.vendor AND o.order_id = o1.order_id and o.ctid < o1.ctid)
WHERE o1.id IS NULL
GROUP BY o.vendor;



------------------------------------

Puedes utilizar una autounión con mayúsculas y minúsculas:

select o.vendor, 
    case when count(*) = count(distinct o1.order_id) 
    then sum(o1.price) 
    else sum(distinct o1.price) 
    end
from orders o 
join orders o1 on o.vendor = o1.vendor and o.order_id = o1.order_id
group by o.vendor;

Salida:

proveedor sumanike 20 adidas 15

Ver demostración.

8

1

Creo que esto todavía no funciona en los casos en que un proveedor tiene varias filas del mismo pedido más al menos una fila de un pedido diferente. Pero me pareció difícil intentar hacer esto en una sola consulta.

- Estrella Azul

27 de marzo de 2021 a las 5:07

@BlueStar Hmm, ¿puedes publicar un ejemplo? Parece que no puedo replicar eso.

-Ajax1234

27/03/2021 a las 14:35

@Ajax1234, creo que para casos como este es de lo que habla BlueStar: dbfiddle.uk/…

-camiseta

27/03/2021 a las 15:50

@tee ¿cuál es el criterio para elegir un precio en ese caso? ¿Debería ser el precio máximo?

-Ajax1234

27/03/2021 a las 15:52

1

No me odies, pero esto todavía no es del todo correcto. Sumar el precio distinto significa que podrías fusionar accidentalmente diferentes pedidos con el mismo precio, como en este violín donde adidas debería sumar 40: dbfiddle.uk/…

- Estrella Azul

27/03/2021 a las 18:15

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare