#sql #oracle #date #oracle11g
Вопрос:
У меня есть запрос oracle sql, чтобы получить даты с 18/05/2021 по 28/05/2021.
По какой-то причине значение после косой черты не считывается, так как значения за 4 месяца также выводятся. Я не знаю, где я ошибаюсь. Пожалуйста, помогите, если можете, большое спасибо за ваше время.
ПРИМЕЧАНИЕ: даты были сохранены в базе данных с типом данных varchar.
SELECT datadate
FROM mytable
WHERE trailerid= '1' and datattime>'05:00:00' and datattime<'12:00:00'
AND datadate between '18/05/2021' and '28/05/2021'
GROUP BY datadate ORDER BY datadate;
Выходной ток
DATADATE
----------------
18/05/2021
19/04/2021
19/05/2021
20/05/2021
21/04/2021
21/05/2021
22/04/2021
22/05/2021
23/04/2021
23/05/2021
24/04/2021
24/05/2021
25/04/2021
25/05/2021
26/04/2021
26/05/2021
27/04/2021
27/05/2021
28/04/2021
28/05/2021
Комментарии:
1. Даты в этом формате не упорядочены, потому что для сравнения дат вам нужно сначала сравнить годы, затем месяцы, затем дни. Порядок этих частей в вашей строке отличается
2. Я не знаю, где я ошибаюсь — примерно в той части, где вы сказали: даты были сохранены в базе данных с типом данных varchar — нет, нет, нет, нет, нет. Исправьте эту фундаментальную проблему, и эта последующая проблема исчезнет навсегда
3. Эй, спасибо, причина, по которой я хотел попробовать это, заключается в том, что в этой колонке у меня были огромные куски данных. Теперь, похоже, мне придется начинать все сначала. Спасибо, что ответили
4. Если вы собираетесь придерживаться хранения дат в виде строк, по крайней мере, храните их в гггг-мм-дд, чтобы МЕЖДУ работами.. Вы жалуетесь, что
BETWEEN '18/05..' AND '28/05..'
возвращает 04 даты, но строка19/04..
действительно находится между ними по той же причине, по которой «M/A» находится между «L/Y» и «Z/Z», хотя A не находится между Y и Z! Честно говоря, потребуется около 5 минут, чтобы добавить еще один столбец типа datetime, скопировать в него данные, удалить старый столбец и переименовать новый обратно в старый. Кроме того, бонус, ваш новый блестящий столбец DATETIME также может хранить содержимое datatime.5. Сохранение дат в виде строки также приведет к искажению статистики оптимизатора, что может привести к плохим планам выполнения
Ответ №1:
Вот что происходит, когда люди хранят значения дат в виде строк.
Посмотрим, поможет ли это:
AND to_date(datadate, 'dd/mm/yyyy') between to_date('18/05/2021', 'dd/mm/yyyy')
and to_date('28/05/2021', 'dd/mm/yyyy')
Комментарии:
1. Эй, спасибо за ваш ответ, но он показывает ошибку 🙁 Это неверное совпадение
2. Именно так, как я сказал — вот что происходит, когда люди хранят значения в виде строк. Некоторые значения в этом столбце не соответствуют формату даты, и Oracle выдает ошибку. Вы ничего не можете с этим поделать, кроме как найти и исправить недопустимые значения. Простой, но неэффективный способ сделать это-использовать цикл и хранить (или отображать) недопустимые строки, чтобы впоследствии их можно было исправить.
3. Ты тоже хотел завернуться
datadate
внутрьto_date
? Я думал, что в этом весь смысл твоего ответа.4. Абсолютно, @mathguy. Спасибо. Я должен стараться не делать несколько вещей одновременно, результат действительно плохой 🙁
Ответ №2:
Вам не нужно начинать все сначала, просто переместите данные в столбец даты и времени
ALTER TABLE t ADD x DATE;
UPDATE t SET x = to_date(concat(datadate,datatime), 'dd/mm/yyyyhh24:mi:ss'))
WHERE datadate in (SELECT to_char(to_date('1999-12-31', 'yyyy-mm-dd') level, 'dd/mm/yyyy') FROM dual CONNECT BY level <= 10000)
Это предложение » ГДЕ » должно генерировать список действительных дат с 2000 по примерно 2030 год — если у вас есть даты за пределами этого диапазона, соответствующим образом скорректируйте
Теперь должна быть возможность находить недопустимые даты (они не были частью предложения where, и x, следовательно, должен оставаться нулевым) и исправлять вручную:
SELECT * FROM t WHERE x is null
Затем удалите файлы datadate и datatime и переименуйте x в datadatetime
Теперь запросы типа «МЕЖДУ» работают правильно, и если вам нужна только часть даты, вы можете выполнить TRUNC(x). (Вы даже можете перейти к другим частям даты, таким как часы, чтобы сократить минуты и секунды или неделю года, чтобы округлить даты до начала недели и т. Д.) Если вам нужно только время, которое вы либо делаете x - TRUNC(x)
, которое дает десятичное число, например, 0,5 для 12 часов дня или 0,75 для 6 вечера, или вы можете выбрать в зависимости от того, что вы хотите сделать. Это было бы x -TRUNC(x) BETWEEN 9.0/24.0 AND 17.0/24.0
лучше сделать, чем сравнивать строки
Комментарии:
1. Хотя ваш общий подход обоснован, в oracle нет типа данных DATETIME. Правильный тип данных для этого приложения-ДАТА (ИЗМЕНИТЬ ТАБЛИЦУ, ДОБАВИТЬ ДАТУ x;)
2. Сделано обновление, спасибо Эд