Некоторые аспекты BETWEEN

  • Автор темы Автор темы ForJest
  • Дата начала Дата начала

ForJest

- свежая кровь
Некоторые аспекты BETWEEN

Всем желающим предлагается развлекательно/поучительный топик по использованию BETWEEN.

1. Часть инициализационная
PHP:
CREATE TABLE min_date (
  id int(11) NOT NULL auto_increment,
  dt_field datetime NOT NULL default '0000-00-00 00:00:00',
  PRIMARY KEY  (id),
  KEY dt_field (dt_field)
) TYPE=MyISAM;

INSERT INTO min_date (id, dt_field) VALUES (1, '2003-02-01 00:00:01');

CREATE TABLE tbl_data (
  id_foreign int(11) NOT NULL default '0',
  d_occurs date NOT NULL default '0000-00-00',
  KEY id_foreign (id_foreign,d_occurs)
) TYPE=MyISAM;

INSERT INTO tbl_data (id_foreign, d_occurs) VALUES 
(1, '2003-02-15'),
(1, '2003-02-16'),
(1, '2003-02-18');

2. Часть - развлекательная
PHP:
SELECT * 
FROM min_date m, tbl_data t 
WHERE m.id=t.id_foreign AND t.d_occurs BETWEEN m.dt_field AND '2004-01-01 23:59:59';
//результат отсутствует, хотя по идее должен был бы

SELECT * 
FROM min_date m, tbl_data t
WHERE m.id = t.id_foreign AND t.d_occurs
BETWEEN '2003-02-01 00:00:01' AND '2004-01-01 23:59:59';
//тоже самое что и первая выборка, по сути, но не исполнению

SELECT * 
FROM min_date m, tbl_data t
WHERE m.id = t.id_foreign AND t.d_occurs >= m.dt_field AND t.d_occurs <= '2004-01-01 23:59:59';
//еще раз тоже самое, другими словами
3. Часть - познавательная.
Ну думаю пытливые умы сами докапаются до истины :)
 
я догадался :) а ForJest специально много лишнего написал :) чтобы сложнее было :)
 
не чтоб сложнее а чтоб интереснее :)
А вообще это кусок реальной задачи... Был... ;)
 
Re: Некоторые аспекты BETWEEN

Автор оригинала: ForJest
t.d_occurs BETWEEN m.dt_field AND '2004-01-01 23:59:59'
А что, мануал по MySQL обещал перевычислять границы для каждой строки выборки? :)
 
А что, мануал по MySQL обещал перевычислять границы для каждой строки выборки?
Еще раз ? что значит перевычислять?
тут вся проблема в некорректном преобразовании DATETIME в DATE просто странно что в одном случае он конвертит а в другом нет.

конечно же такие дела вообще некорректны с этим никто не спорит :)
 
там у них была бага с преобразованием DATETIME, DATA, TIMESTAMP, возможно это отголоски той самой.
А вообще подобное некорректное поведение описывается в официальном списке рассылки, а не на форуме.
 
Автор оригинала: .des.
Еще раз ? что значит перевычислять?
Оптимизатор у MySQL странноватый. Он вполне мог зафиксировать значение параметра between для первого попавшегося значения m.dt_field.
 
Апельсин - сорри я просто даже не подумал что это может быть бага... Я думал это фича - поэтому и решил что это просто аспекты и предложил развлечься с поиском почему :)

expr BETWEEN min AND max
-- If expr is greater than or equal to min and expr is less than or equal to max, BETWEEN returns 1, otherwise it returns 0. This is equivalent to the expression (min <= expr AND expr <= max) if all the arguments are of the same type. The first argument (expr) determines how the comparison is performed as follows:
-- If expr is a TIMESTAMP, DATE, or DATETIME column, MIN() and MAX() are formatted to the same format if they are constants.
-- If expr is a case-insensitive string expression, a case-insensitive string comparison is done.
-- If expr is a case-sensitive string expression, a case-sensitive string comparison is done.
-- If expr is an integer expression, an integer comparison is done.
-- Otherwise, a floating-point (real) comparison is done.

Итак получается:
1. Операнды не одного типа
2. Операнды MAX и MIN не константы.
У меня нет никаких других предположений кроме:
DATE и DATETIME в таком случае рассматриваются в INTEGER контексте.
Т.е. имеем для что-то типа
20030216 BETWEEN 20030201000001 AND 20040101235959
Соответственно даное условие будет ложным.

Оптимизатор у MySQL странноватый. Он вполне мог зафиксировать значение параметра between для первого попавшегося значения m.dt_field.
Но ведь в тестовом примере всего 1 запись в этой таблице - это же ничего не меняет, получается.
 
Чтобы логично закрыть заявленую тему трэда.
Аспект состоит в том что
expr BETWEEN min AND max
это не
(min <= expr AND expr <= max).
Так как я с этим столкнулся случайно, думаю даже опытному разработчику стоит об это узнать и помнить при составлении запросов. А пример просто показывает к чему это может привести.
А посты наглядно показывают чем это может считаться в сознании программера :).
Никого не хотел обидеть/дискредитировать, если что - сорри.
 
Кстати у меня то же неточности с использованием BETWEEN, которые пропали используя >= AND <=
 
точно помню что в changelog 4.0.5 был исправлен глюк с BETWEEN (после обновления у меня пропал глюк)

D.3.8 Changes in release 4.0.5 (13 Nov 2002)
BETWEEN behaviour changed (see section 6.3.1.2 Comparison Operators). Now datetime_col BETWEEN timestamp AND timestamp should work as expected.

P.S. .. чтобы логично закрыть тему треда...
 
Риторический вопрос: вот не понимаю, какой работы с датами/временем вы ждали от СУБД, разработчики которой считают, что в году 13 месяцев, а в каждом из месяцев по 32 дня? :D
 
Sad Spirit :D ну как же без "тонкого" намека на Postgre :D
 
Автор оригинала: .des.
Sad Spirit :D ну как же без "тонкого" намека на Postgre :D
Это тонкий намёк несколько на другое... Какой смысл говорить о мелких багах работы с датами, если в поле типа "дата" можно засунуть значение, датой a priori не являющееся? ;)

Что больше: '25 часов 05 минут 30 февраля 2003 года' или '1 час 00 минут 31 февраля 2003 года'?
 
> Какой смысл говорить о мелких багах работы с датами, если в поле типа "дата" можно засунуть значение, датой a priori не являющееся?

потому как первое - больше смахивает на багу, а второе - документированная фича ;)
 
странно, у меня либа на Nested Sets полностью построена на BETWEEN, в котором нередко появляются и поля из "той же записи", плюс к тому же ещё разные IF()'ы и т.п.
ни разу не замечал глюков, всё работает как часы.

может не стоит так сразу категорично отзываться о BETWEEN, призывая от него отказываться?

может надо было таки дату приводить к числу перед численным сравнением - 0+'2004-01-01 23:59:59' - так, как это указано в мане?
 
D.3.8 Changes in release 4.0.5 (13 Nov 2002)
BETWEEN behaviour changed (see section 6.3.1.2 Comparison Operators). Now datetime_col BETWEEN timestamp AND timestamp should work as expected.

P.S. .. чтобы логично закрыть тему треда...
Этот "глюк" отношения не имеет к тестовому примеру.

Кстати у меня то же неточности с использованием BETWEEN, которые пропали используя >= AND <=
может не стоит так сразу категорично отзываться о BETWEEN, призывая от него отказываться?
Я не призывал отказываться от BETWEEN :) Я призывал прочитать ман и помнить, что BETWEEN работает таже как >= <= только в заявленных документацией случаях. В первых же строчках об этом прямо сказано. Это и есть аспекты BETWEEN. Никто не говорит про багу или глюки.

BETWEEN это не >= <=. Я для себя это обнаружил и счастлив поделиться с остальными. К датам этот трэд имеет только косвенное отношение :)

P.S. Хотя не мне вас всех учить ;). Всем спасибо за внимание к.
 
вы пробовали свой тест на версии >4.0.5 ?
Нет - не тестировал. Может я излишне категорично высказался. Но в тестовом примере идет разница на том что
expr - выражение типа DATE
min - выражение типа DATETIME
max - строковая константа, содержащая литерал DATETIME.
 
Сверху