Фильтровать строки, в которых 2 значения столбца отображаются более одного раза

#sql #oracle #group-by #having

#sql #Oracle #группировать по #имея

Вопрос:

У меня есть таблица, подобная:

 SELECT
s.date,
s.orderid,
s.num1,
s.num2,
s.sales,
s.price
FROM sales AS s
 

В результате

 date       | orderid | num1 | num 1 | sales | price
2020-11-01 | 1       | a    | aa    | 1     | 10
2020-11-01 | 8       | k    | kk    | 1     | 10
2020-11-02 | 1       | a    | aa    | -1    | 10
2020-11-01 | 2       | b    | bb    | 2     | 8
2020-11-01 | 3       | c    | cc    | 1     | 10
2020-11-01 | 3       | c    | cc    | 2     | 9
2020-11-04 | 18      | u    | uu    | 5     | 2
 

«orderid» и «num1» должны появиться только один раз, в противном случае это возврат (вторая запись имеет значение «продажи» -1, что отрицает предыдущие продажи.
Итак, мне нужно полностью удалить эти записи (не сохраняя строку). В противном случае «orderid» не имеет никакого значения и не нужен.

Я хочу сгруппировать по «дате», «num1» и «num2», суммируя все продажи и получая среднюю цену при удалении идентификаторов заказов num1, которые появляются более одного раза вместе.

Конечный результат должен быть:

 date       | orderid | num1 | num 1 | sales | price
2020-11-01 | 8       | k    | kk    | 1     | 10
2020-11-01 | 2       | b    | bb    | 2     | 8
2020-11-01 | 3       | c    | cc    | 3     | 9.5
2020-11-04 | 18      | u    | uu    | 5     | 2
 

Как я могу сделать это с помощью Groupby? Пока у меня есть это:

 SELECT
s.date,
s.num1,
s.num2,
SUM(s.sales),
AVG(s.price)
FROM sales AS s
GROUP BY s.date, s.num1, s.num2
 

Ответ №1:

Вы можете использовать оконные функции. На основе вашего описания (удаление заказов, которые появляются более одного раза), вы можете использовать count(*) :

 select s.date, s.num1, s.num2, SUM(s.sales), AVG(s.price)
from (select s.*, count(*) over (partition by orderid, num1) as cnt
      from sales s
     ) s
where cnt = 1
group by s.date, s.num1, s.num2;
 

Я подозреваю, что вы действительно хотите row_number() , поэтому сохраните одну из повторяющихся строк.

Комментарии:

1. Нет, мне не нужно сохранять строку, возвраты должны быть полностью отфильтрованы.

2. @Vega . . . Так что мое подозрение неверно, но ответ правильный.

Ответ №2:

Вы можете использовать group by и having следующим образом:

 SELECT max(s.date) as date,
       S.orderid,
       s.num1,
       s.num2,
       SUM(s.sales),
       AVG(s.price)
  FROM sales AS s
GROUP BY s.orderid, s.num1, s.num2
Having sum(sales) > 0;
 

Ответ №3:

Вопрос:

Это журнал транзакций, в котором у вас есть OrderID 1 с записями продаж 10, 5, -1, 7, 8, что должно привести к значению 15? 10 и 5 отрицаются значением -1. Если это так, вам нужно выполнить запрос, который a) находит все строки после последнего -1 для этого OrderID и суммирует значения продаж.

Примером этого являются значения продаж для одного и того же идентификатора заказа 5, 6, -1, 7, 9, -1, 10, 2 который должен использовать только 10 и 2 для окончательной суммы

Что-то вроде

Запрос 1 — найдите максимальное значение (дата) для каждого идентификатора заказа, где сумма продаж равна -1 Запрос 2 — Используйте запрос 1, чтобы получить все транзакции для каждого идентификатора заказа, где дата> дата в запросе 1

С ПОМОЩЬЮ (определите запрос 1 здесь)
ВЫБЕРИТЕ s.OrderID, Sum(s.sales) как TotalSales, Avg(s.Price) как AveragePrice
ИЗ
ЛЕВОГО ВНЕШНЕГО СОЕДИНЕНИЯ sales (запрос 1) q1 ДЛЯ q1.OrderID
, ГДЕ (q1.Date равно нулю) ИЛИ (s.Date> q1.Дата)
ГРУППИРОВАТЬ ПО s.OrderID

Комментарии:

1. Это журнал продаж в базе данных Oracle. Каждая продажа регистрируется в строке, затем, если клиент возвращает товар, создается другая запись с тем же orderid и num1, но с отрицательным количеством, так что продажа возврат = продажа 0. Но мне нужно удалить их все вместе для моего варианта использования.