2014-09-05 2 views
0

До сих пор я придумал ниже:множественный экстракт() с предложением WHERE?

WHERE (extract(month FROM orders)) = 
        (SELECT min(extract(month from orderdate)) 
        FROM orders) 

Однако, что будет, следовательно, возвращать ноль многих строк, и в моем случае, много, потому что много заказов существуют в том же самом раннем (минимум) в месяц, т.е. 4 февраля, 9 февраля, 15 февраля, ...

Я знаю, что предложение WHERE может содержать несколько столбцов, так почему бы не работать ниже?

WHERE (extract(day FROM orderdate)), (extract(month FROM orderdate)) = 
        (SELECT min(extract(day from orderdate)), min(extract(month FROM orderdate)) 
        FROM orders) 

Я просто получаю: SQL Error: ORA-00920: invalid relational operator

Любая помощь будет здорово, спасибо!

Образец данных: 02-Feb-2012 14-февраля-2012 22-Dec-2012 09-февраля-2013 18-Июль-2013 01-Jan-2014

Выход: 02-Feb-2012 14-февраля-2012

Желаемая выход: 02-Feb-2012

+0

ОПИСАНИЕ _WHERE может содержать несколько столбцов, которые действительны только для подзапроса, afaik – Sathya

+0

Я не понимаю требования из вашего описания, можете ли вы опубликовать небольшой набор выборочных данных вместе с ожидаемым выходом? – ninesided

+0

Конечно, извините за путаницу. Добавлено в OP. (Извините за форматирование ... не уверен, как с этим бороться) – Restricted

ответ

0

использовать что-то вроде этого:

with cte1 as (
    select 
     extract(month from OrderDate) date_month, 
     extract(day from OrderDate) date_day, 
     OrderNo 
    from tablename 
), cte2 as (
    select min(date_month) min_date_month, min(date_day) min_date_day 
    from cte1 
) 
select cte1.* 
from cte1 
where (date_month, date_day) = (select min_date_month, min_date_day from cte2) 

Общее выражение таблицы позволяет вам реструктурировать ваши данные, а затем использовать эти данные для выбора. Первый cte-block (cte1) выбирает месяц и день для каждой из ваших строк таблицы. Cte2 затем выбирает мин (месяц) и мин (дата). Последний select затем объединяет оба ctes, чтобы выбрать все строки из cte1, которые имеют желаемый месяц и день.

Возможно, это более короткое решение, однако мне нравятся общие табличные выражения, так как они почти все время лучше понимать, чем «оптимальный, самый короткий» запрос.

+0

Я не знаю о множественных функциях извлечения, мне обычно нравится избегать сложных, трудночитаемых вещей, подобных этому, и заменить его на что-то, что легко понять, хотя, вероятно, это больше написано. Я добавил немного объяснений. Если вам нужна дополнительная помощь, пожалуйста, поставьте полную структуру таблицы, и я дам вам окончательный запрос. –

+0

Спасибо. Я не уверен, что вы подразумеваете под полной структурой таблицы. то есть имена атрибутов и определенные типы данных? Я не уверен, что еще добавить, но это просто таблица (называемая Orders) с двумя атрибутами. OrderNO, OrderDate, с указанием количества и даты в качестве их типов данных соответственно. Я сомневаюсь, что вы ссылались на фактические данные таблицы, однако, если вы этого требуете, сообщите мне. Я ценю помощь Томаса. Кроме того, я бы предпочел не использовать cte, если все в порядке, возможно, в будущем. – Restricted

+0

Я отредактировал ответ, чтобы отразить имена столбцов. Был бы еще один подход, который я мог бы предложить. Вы можете просто сделать «месяц * 100 + день» и использовать этот «виртуальный» столбец для заказа своих строк. –

2

Я воссоздал ваш стол и узнал, что вы немного испортили скобки. Следующие работы для меня:

where 
    (extract(day from OrderDate),extract(month from OrderDate)) 
    = 
    (select 
     min(extract(day from OrderDate)), 
     min(extract(month from OrderDate)) 
    from orders 
    ) 
+0

Спасибо Томас. Однако, с несколькими extract(), я сталкиваюсь с «никакими строками не выбранными». Я понятия не имею, почему, и похоже, что мне нужно идти по этому пути по-другому ... – Restricted

+0

Смотрите комментарий от Eat a Peach ниже: «Извлечение min день и месяц отдельно не верно. Например, если у вас есть 10 января и 3 февраля, как даты, вы получите результат 3-го января, что явно неверно ». Вам нужно будет сначала выбрать минутный месяц, а затем минимальный день в этом месяце, а не общий месяц и месяц.Но вы просили что-то другое. –

+0

Верно, я вижу. Поэтому, чтобы включить несколько гнезд подзапросов, чтобы весь оператор выглядел достаточно запутанным, хотя не так ли? Проще говоря, я хотел, чтобы это было просто с базовыми командами SQL, возможно ли это? – Restricted

0

Если это действительно то, что вы хотите, так странно, как кажется, тогда как другой подход можно забыть настои и подзапрос к таблице, чтобы получить минимальные и использование аналитический подход вместо:

select orderdate 
from (
    select o.*, 
    row_number() over (order by to_char(orderdate, 'MMDD')) as rn 
    from orders o 
) 
where rn = 1; 

ORDERDATE 
--------- 
01-JAN-14 

row_number() эффективно добавляет псевдо-столбец каждой строки в исходной таблице, основываясь на месяц и день в дату заказа. Значения rn уникальны, поэтому будет одна строка, помеченная как 1, которая будет с самого раннего дня в самый ранний месяц. Если у вас несколько заказов с одним и тем же днем ​​/ месяцем, скажем 01-янв-2013 и 01-янв-2014, то вы все равно получите ровно один с rn = 1, но выбранный является неопределенным. Вам нужно будет добавить еще order by условий, чтобы сделать его детерминированным, но я понятия не имею, что вы можете пожелать.

Это делается во внутреннем запросе; внешний запрос затем фильтрует, чтобы возвращались только записи, отмеченные rn = 1; поэтому вы получите ровно одну строку от общего запроса.

Это также позволяет избежать ситуации, когда номер раннего дня не находится в самом раннем номере месяца - скажем, если вы только имели 01-янв-2014 и 02-фев-2014; сравнение дня и месяца отдельно будет искать 01-фев-2014, которого не существует.

SQL Fiddle (с добавлением анкера Томаса Черчиха, дающего тот же результат для этих данных).


Чтобы присоединиться результат против вашей таблицы счета, вам не нужно снова присоединиться к столу заказов - тем более не с крестом присоединиться, который перекос результаты. Вы можете сделать присоединиться (по крайней мере) два способа:

SELECT 
    o.orderno, 
     to_char(o.orderdate, 'DD-MM-YYYY'), 
    i.invno 
FROM 
    (
    SELECT o.*, 
     row_number() over (order by to_char(orderdate, 'MMDD')) as rn 
    FROM orders o 
) o, invoices i 
WHERE i.invno = o.invno 
AND rn = 1; 

Или:

SELECT 
    o.orderno, 
     to_char(o.orderdate, 'DD-MM-YYYY'), 
    i.invno 
FROM 
    (
    SELECT orderno, orderdate, invno 
    FROM 
     (
     SELECT o.*, 
      row_number() over (order by to_char(orderdate, 'MMDD')) as rn 
     FROM orders o 
    ) 
    WHERE rn = 1 
) o, invoices i 
WHERE i.invno = o.invno; 

Первый выглядит, как он делает больше работы, но планы выполнения одинаковы.

SQL Fiddle с вашим запросом на получение макаронных изделий, который получает два ряда назад, и эти два, которые его получают.

+0

ОК, неохотно изменил ответ и SQL-скрипт на соединения старого стиля. Ваше крест-соединение ничего не делало и просто дублировало строки. Я сохранил внутреннее соединение между встроенным представлением против 'objects' и' invoices'; это просто лишние скрещенные «заказы», ​​которые были проблемой. –

+0

Righteo, что имеет смысл - отлично. Спасибо, что забрал меня Алекс. Рад, что в этом сообществе есть такие чрезвычайно полезные люди. Отличный день, ура. – Restricted

Смежные вопросы