Выберите одну строку с отличным значением одного столбца - PullRequest
5 голосов
/ 25 ноября 2011

Это данные

id    name     start_date    end_date    merchant_id
===================================================
111   name1    25-nov-11    31-jan-12    9999
222   name2    23-nov-11    25-dec-11    9999
333   name3    25-nov-11    25-nov-12    9999
444   name4    20-nov-11    20-nov-11    9999
555   name5    25-nov-11    25-dec-11    8888
666   name6    19-oct-11    20-nov-11    8888
777   name7    20-nov-11    20-jun-12    8888

Мне нужно отсортировать все строки по start_date (desc), где start_date<=today и end_date >=today, но с ограничением 1 на merchant_id. Это означает, что если запрос находит более одной строки, просто верните первую.


Тестовый скрипт

CREATE TABLE DEAL
(
  ID            VARCHAR2(40 BYTE)       NOT NULL,
  NAME          VARCHAR2(255 BYTE),
  START_DATE    DATE,
  END_DATE      DATE,
  MERCHANT_ID   NUMBER(22),
 CONSTRAINT DEAL PRIMARY KEY (ID)
);

INSERT ALL
INTO DEAL (ID,NAME,START_DATE,END_DATE,MERCHANT_ID) VALUES ('111','name1','25-nov-11','31-jan-12','9999')
INTO DEAL (ID,NAME,START_DATE,END_DATE,MERCHANT_ID) VALUES ('222','name2','23-nov-11','25-dec-11','9999')
INTO DEAL (ID,NAME,START_DATE,END_DATE,MERCHANT_ID) VALUES ('333','name3','25-nov-11','25-nov-12','9999')
INTO DEAL (ID,NAME,START_DATE,END_DATE,MERCHANT_ID) VALUES ('444','name4','20-nov-11','20-nov-11','9999')
INTO DEAL (ID,NAME,START_DATE,END_DATE,MERCHANT_ID) VALUES ('555','name5','25-nov-11','25-dec-11','8888')
INTO DEAL (ID,NAME,START_DATE,END_DATE,MERCHANT_ID) VALUES ('666','name6','19-oct-11','20-nov-11','8888')
INTO DEAL (ID,NAME,START_DATE,END_DATE,MERCHANT_ID) VALUES ('777','name7','20-nov-11','20-jun-12','8888')
SELECT * FROM dual;

работает так:

SELECT DISTINCT merchant_id, id, name, start_date, end_date FROM deal WHERE start_date <= trunc(sysdate) AND end_date >= trunc(sysdate) ORDER BY start_date DESC;

не возвращает желаемый результат, поскольку один и тот же идентификатор продавца возвращается несколько раз:

MERCHANT_ID  ID  NAME  START_DATE  END_DATE 
===========================================
9999         111  name1  25-NOV-11  31-JAN-12  
9999         333  name3  25-NOV-11  25-NOV-12 
8888         555  name5  25-NOV-11  25-DEC-11  
9999         222  name2  23-NOV-11  25-DEC-11  
8888         777  name7  20-NOV-11  20-JUN-12

Ответы [ 4 ]

2 голосов
/ 25 ноября 2011

Следующий запрос Oracle должен делать то, что вам нужно:

SELECT *
FROM (
    SELECT TABLE1.*, DENSE_RANK() OVER(PARTITION BY MERCHANT_ID ORDER BY START_DATE DESC, ID) R
    FROM TABLE1
    WHERE SYSDATE BETWEEN START_DATE AND END_DATE
)
WHERE R = 1
ORDER BY START_DATE DESC

По сути, он сначала фильтрует строки по дате, а затем игнорирует все строки, кроме первой , которые имеют одинаковый MERCHANT_ID.

Обратите внимание, что значение "first" определяется по убыванию START_DATE. Если две строки имеют одинаковый START_DATE, то «спор» разрешается с использованием порядка идентификаторов.

0 голосов
/ 25 ноября 2011

Все эти другие ответы кажутся очень сложными ... Вы можете использовать модификатор DISTINCT в Oracle, чтобы получить одну и только одну уникальную строку для каждого столбца.Вот запрос, который вы могли бы использовать для получения нужных вам данных, учитывая структуру таблицы в вашем сообщении:

SELECT DISTINCT merchant_id, id, name, start_date, end_date FROM table WHERE start_date >= today AND end_date < today ORDER BY start_date DESC

0 голосов
/ 25 ноября 2011

В зависимости от того, какой тип sql вы используете (mysql, sql server и т. Д.), Будут альтернативные ответы.

Например, на сервере sql вы можете сказать «Назначить каждой строке номер, начиная с 1 для каждого продавца», и всегда выбирать номер 1.

В общем sql, вы должны быть немного менее прямой. Кажется, ваш столбец идентификаторов гарантированно будет уникальным? Если так, то один из способов сформулировать вопрос - «получить записи внутри диапазона дат, ГДЕ в том же диапазоне дат нет более высокого идентификатора для одного и того же продавца»

Вы уже знаете, как фильтровать по> и <сегодня? Я думаю, что ответ на вопрос, как это сделать, зависит от типа используемого вами sql: </p>

Так что попробуйте:

SELECT * from myFavoriteTable
  WHERE today() < end_date and today > start_date -- for this date criteria use whatever works
  AND NOT EXISTS ( SELECT * from myFavoriteTable as TooLow
      WHERE today() < end_date and today() > start_date -- as above
      AND TooLow.Merchant = myFavoriteTable.merchant
      AND TooLow.id > myFavoriteTable.id)
0 голосов
/ 25 ноября 2011

Привет что-то вроде этого может работать:

select id,    name,     start_date,    end_date from (
select id,    name,     start_date,    end_date, ROW_NUMBER()
   OVER (PARTITION BY merchant_id ORDER BY merchant_id) AS rnum from your_table
   where start_date<=trunc(sysdate) and end_date>=trunc(sysdate))
   where rnum=1
order by start_date desc

, если вы предоставите простой тестовый скрипт для создания и заполнения таблицы, я могу дать вам правильный запрос.

...