информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
За кого нас держат?Все любят мед
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Три миллиона электронных замков... 
 Doom на газонокосилках 
 Умер Никлаус Вирт 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
если вы видите этот текст, отключите в настройках форума использование JavaScript
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
Ага, таки сильно ошибался я, а не Winer 02.03.11 00:31  Число просмотров: 1474
Автор: Fighter <Vladimir> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
<programming>
[SQL] Можно ли в SQL-запросе общащаться к перменной типа Date как к структуре? 24.02.11 08:19  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
Отредактировано 24.02.11 08:20  Количество правок: 1
<"чистая" ссылка> <обсуждение закрыто>
Работаю в MS Ассеss. Есть таблица list (id, date, title). Поле date имеет тип «Полный формат даты» (например, 19.06.1994 17:34:23). Можно ли с помощью SQL-запроса выбрать записи с конкретным днём, месяцем или годом? Т.е. можно ли как-то исхитриться, чтобы заработал такой запрос: «SELECT * FROM list WHERE date.year = 1994»?

У меня есть идеи по поводу того, как решить эту задачи, но они громоздкие, хотелось бы найти что-нибудь попроще. Одна из идей – это перед выполнением запроса динамически генерировать временную таблицу, где под каждый параметр даты отводить отдельное поле и делать выборку уже из этой таблицы.
Как вариант, дату можно представить iso форматом (yyyymmdd... 24.02.11 14:43  
Автор: Den <Denis> Статус: The Elderman
Отредактировано 24.02.11 14:44  Количество правок: 1
<"чистая" ссылка> <обсуждение закрыто>
Как вариант, дату можно представить ISO форматом (YYYYMMDD или YYYYMMDDhhmmss) в строке и работать как со строкой. Например:
select * from list where date like '1994%' -- YEAR
select * from list where date like '____06%' -- MONTH
select * from list where date like '______19%' -- DAY
Большое спасибо, с LIKE’ом действительно, получается то, что... 25.02.11 11:15  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
Большое спасибо, с LIKE’ом действительно, получается то, что нужно (только в аксесе вместа знака % используется *, а вместо _ - ?). Вот только появилась новая проблема – каким образом формировать динамически нужный запрос?

Т.е. у меня есть две таблицы: list (id, date, title), years (id, title), Есть запрос «SELECT * FROM list WHERE date like '???12*';». Если я просто создам запрос обычными средствами Access и помещу туда данную строку, то всегда будет выполняться одно и то же.

Средствами Access можно в подчинённой форме указывать запрос, вот только я не понимаю, как передавать ему параметры. Допустим. есть форма-таблица со списком годов. Как сделать так, чтобы при нажатии на «+» управление передавалось в процедуру VBA, которая бы подставляла в LIKE соответствующую строку? Пробовал на разные события вешать обработчик, но что-то не получилось.

Если я сделаю такой запрос: «SELECT * FROM list WHERE date like mask», то как мне вовремя подставить нужное значение в переменную mask, чтобы не выпадало окошко для ввода параметра вручную?
непосретственно из запроса ты можешь ссылаться на переменную... 25.02.11 20:38  
Автор: Den <Denis> Статус: The Elderman
Отредактировано 25.02.11 20:41  Количество правок: 2
<"чистая" ссылка> <обсуждение закрыто>
непосретственно из запроса ты можешь ссылаться на переменную или объект формы, типа:
select * from list where list.date like Str(Year([frmMy]![editDate])) & "*"
или
select * from list where list.date like Str(DatePart("yyyy"), [frmMy]![editDate]) & "*"

еще можно строить запрос собираю строку в коде VB и записывать в свойство .SQL запроса:
myquery.sql = "select * from list where list.date like '" & Str(Year(Me.editDate.value)) & "*' "
Что-то не получается. пищу: «select * from list where date... 01.03.11 10:58  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
Что-то не получается. Пищу: «SELECT * FROM list WHERE date Like '??????' & Str(year!title);». Форма открывается, запрос выполняется, editbox из формы year!title видит (окошко с запросом ввода переменной не выскакивает), но запрос возвращается пустым. Если вручную вместо «Str(year!title)» подставить, например, ‘2000’, то запрос выполняется адекватно. Что я делаю не так.

Ещё по второму случаю вопрос. Не совсем понятна последовательность действий. Вот у меня есть родительская форма… А дальше не понятно, что делать. Когда запрос уже есть всё ясно – создаём подчинённую форму и связываем её с этим запросом, а в случае, если я динамически запрос создаю, то что делать после создания родительской формы? Если подчинённую форму создавать, то что ей в источник записей ставить, а если этот динамически сформированный запрос записывать в реально существующий, то по какому событию это делать? Я пытался методом тыка события перебрать, чтобы до выполнения запроса вклиниться, но что то так и не нашёл нужного.
Ещё меня интересует, как непосредственно из VB с запросами... 02.03.11 14:11  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
Ещё меня интересует, как непосредственно из VB с запросами работать. Полный вопрос в верхнем сообщении. В бейсике хоть отладку можно вести, можно увидеть, что там в запросе получилось...
Например так: 02.03.11 23:36  
Автор: Den <Denis> Статус: The Elderman
Отредактировано 02.03.11 23:39  Количество правок: 4
<"чистая" ссылка> <обсуждение закрыто>
Например так:
Dim qryMy as QeryDef
Set qryMy = CurrentDatabase.QueryDefs("MyQuery")
With qryMy
  .SQL = "SELECT *" & vbNewLine & _
    "  FROM List" & vbNewLine & _
    "  WHERE timestamp >= #01.01." & CStr(Year(Now())) & "#" & vbNewLine & _
    "    AND timestamp < #01.01." & CStr(Year(Now())+1) & "#"
End With

---

P.S. вместо CurrentDatabase нужно использовать то, что рекомендуется для конкретной версии Access и конкретного типа проекта. F1 тебе в помощь!
"select * from list where date like '??????" &... [upd] 01.03.11 12:02  
Автор: Den <Denis> Статус: The Elderman
Отредактировано 01.03.11 12:30  Количество правок: 2
<"чистая" ссылка> <обсуждение закрыто>
"SELECT * FROM list WHERE date Like '" & Str(year!title) & "????'"

если date в формате YYYYMMDD
Я для простоты текстовое поле обычное сделал, но не работает. 01.03.11 13:09  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
Моя ошибка. в VB надо использовать функцию CStr, а не Str [upd] 01.03.11 13:44  
Автор: Den <Denis> Статус: The Elderman
Отредактировано 01.03.11 23:33  Количество правок: 3
<"чистая" ссылка> <обсуждение закрыто>
SELECT * FROM List WHERE List.date Like CStr(Year([formSelect]![editDate])) & '????';

Очень рекомендую хранить дату в строке именно в ISO формате, чтобы быстрее работало упорядочивание по дате с использованием индекса.
Попробовал последовать вашей рекомендации, и совершенно... 02.03.11 14:08  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
Попробовал последовать вашей рекомендации, и совершенно запутался. Не представляю, как запрос отлаживать, чтобы посмотреть, что там за строка для LIKE'а получилась. Вы говорите про ISO-формат. Я поменял тип поля tile вместо строки на краткий формат даты, например, 01.01.1900. Но если это уже не строка, то в каком виде оно доходит до запроса? Со строкой хоть можно было предсказуемый результат получить, а тут вообще непонятно, что в LIKE для примера вписывать. Например, 01.01.1900 в каком виде доходит? 01011900, 19000101 или что-то ещё?

PS. С CStr тоже не работает.

PPS. А если я не строкой, а числом буду иднекс по годам делать?Это же тоже должно быстро работать? Зачем мне дни и месяцы в иднексе, где только год нужен.
оператор LIKE проверяет строковое выражение (символьное поле... 02.03.11 23:16  
Автор: Den <Denis> Статус: The Elderman
Отредактировано 03.03.11 14:41  Количество правок: 2
<"чистая" ссылка> <обсуждение закрыто>
> Попробовал последовать вашей рекомендации, и совершенно
> запутался. Не представляю, как запрос отлаживать, чтобы
> посмотреть, что там за строка для LIKE'а получилась. Вы
> говорите про ISO-формат.

оператор LIKE проверяет строковое выражение (символьное поле таблицы) на совпадение заданному шаблону.

> Я поменял тип поля tile вместо
> строки на краткий формат даты, например, 01.01.1900. Но
> если это уже не строка, то в каком виде оно доходит до
> запроса?

Ни в каком. Некоторые БД работают с датой как со строкой, но в случае Access, это врядли получится.

> Со строкой хоть можно было предсказуемый результат
> получить, а тут вообще непонятно, что в LIKE для примера
> вписывать. Например, 01.01.1900 в каком виде доходит?
> 01011900, 19000101 или что-то ещё?

если решил использовать формат даты, то можно воспользоваться советом kstati и использовать оператор between. Но если предполагается использовать только выборку за год, то проще использовать >= и <
Например
WHERE list.timestamp >= #01.01.2010# AND list.timestamp < #01.01.2011#
проще некуда и приобразовывать ничего не надо.

> PS. С CStr тоже не работает.

Функция СStr() всего лишь приобразовывает данные числового формата в строку.

> PPS. А если я не строкой, а числом буду иднекс по годам
> делать?Это же тоже должно быстро работать? Зачем мне дни и
> месяцы в иднексе, где только год нужен.

а смысл? я до сих пор не могу понять цели всех этих манипуляций. ты скажи - что в итоге надо получить?
в таком случае используй between. В запросах с like и функциями типа Year по дате приходится смотреть все кортеджи, ибо, как ты и сказал "это уже не строка" - приходится производить преобразование даты в строку, затем сравнивать like, 02.03.11 14:19  
Автор: kstati <Евгений Борисов> Статус: Elderman
Отредактировано 02.03.11 14:21  Количество правок: 3
<"чистая" ссылка> <обсуждение закрыто>
Не знаю, есть ли это в убогом Аксессе, но в MySQL есть... 24.02.11 09:21  
Автор: Winer <Виктор С.> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
> Работаю в MS Ассеss. Есть таблица list (id, date, title).
> Поле date имеет тип «Полный формат даты» (например,
> 19.06.1994 17:34:23). Можно ли с помощью SQL-запроса
> выбрать записи с конкретным днём, месяцем или годом? Т.е.
> можно ли как-то исхитриться, чтобы заработал такой запрос:
> «SELECT * FROM list WHERE date.year =
> 1994»?

Не знаю, есть ли это в убогом Аксессе, но в MySQL есть оператор BETWEEN. С его помощью ты сможешь выбрать записи от 01.01.1994 00:00:00 до 31.12.1994 23:59:59
Вообще-то в MySQL это делается по другому ) и гораздо изящнее: 24.02.11 11:05  
Автор: Fighter <Vladimir> Статус: Elderman
Отредактировано 24.02.11 11:06  Количество правок: 1
<"чистая" ссылка> <обсуждение закрыто>
> > Работаю в MS Ассеss. Есть таблица list (id, date,
> title).
> > Поле date имеет тип «Полный формат даты» (например,
> > 19.06.1994 17:34:23). Можно ли с помощью SQL-запроса
> > выбрать записи с конкретным днём, месяцем или годом?
> Т.е.
> > можно ли как-то исхитриться, чтобы заработал такой
> запрос:
> > «SELECT * FROM list WHERE date.year
> =
> > 1994»?
>
> Не знаю, есть ли это в убогом Аксессе, но в MySQL есть
> оператор BETWEEN. С его помощью ты сможешь выбрать записи
> от 01.01.1994 00:00:00 до 31.12.1994 23:59:59
Вообще-то в MySQL эт оделается по другому )
SELECT * FROM list WHERE YEAR(`date`)='1994'
где YEAR() - функция, возвращающая номер года той даты, которую ей скормили. Есть еще функции DAY() и MONTH(), если нужно.
Неоптимальное с точки зрения индекса решение, если я не... 24.02.11 12:15  
Автор: Winer <Виктор С.> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
> > Не знаю, есть ли это в убогом Аксессе, но в MySQL есть
> > оператор BETWEEN. С его помощью ты сможешь выбрать
> записи
> > от 01.01.1994 00:00:00 до 31.12.1994 23:59:59
> Вообще-то в MySQL эт оделается по другому )
> SELECT * FROM list WHERE YEAR(`date`)='1994'
> где YEAR() - функция, возвращающая номер года той даты,
> которую ей скормили. Есть еще функции DAY() и MONTH(), если
> нужно.

Неоптимальное с точки зрения индекса решение, если я не ошибаюсь. Надо перелопатить все строки с применением к ним функции и сравнить с необходимым значением. В случае BETWEEN, если я не ошибаюсь, индексы нормально задействуются.
Отнюдь ) при использовании between индексы используюся активно. Кстати говоря напоминаю, что есть очень удобный инструмент анализа запросов. имя ему `describe` ;)[upd] 01.03.11 23:06  
Автор: kstati <Евгений Борисов> Статус: Elderman
Отредактировано 02.03.11 01:15  Количество правок: 14
<"чистая" ссылка> <обсуждение закрыто>
Одна из задач индексов - быстрая сортировка значений для выборки.
В случае использования between по индексированному полю идёт поиск малого значения, затем выдача результата вплоть до большего значения.

Выгода очевидна, по скорости. А причина - количество затрагиваемых строк (в моём случае 30480 против 762707), которые обусловлены типом запроса range и index соответственно; При этом вариант "where YEAR(`d`) " даже не пытается использовать ключи.

Теста ради набил таблицу хламом - случайными датами за 50 лет:

insert into tests.date_test values (NOW() - interval floor(rand()*365*50) day);

А за тем выбрал данные за 2001 год.
Если работа ведётся именно с диапазоном, то between рулит. Ясное дело, если нужно выбрать к примеру все первые числа, то ой )

mysql> describe date_test;
+-------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------+------+-----+---------+-------+
| d     | date | YES  | MUL | NULL    |       |
+-------+------+------+-----+---------+-------+
1 row in set (0.00 sec)

mysql> select distinct count(*) from date_test;
+----------+
| count(*) |
+----------+
|   762061 |
+----------+
1 row in set (0.77 sec)



mysql> select count(*) from date_test where YEAR(`d`) = 2001;
+----------+
| count(*) |
+----------+
|    15401 |
+----------+
1 row in set (0.80 sec)

mysql> select count(*) from date_test where `d` like "2001%";
+----------+
| count(*) |
+----------+
|    15401 |
+----------+
1 row in set, 1 warning (0.84 sec)

mysql> select count(*) from date_test where  `d` between '2001-01-01' and '2001-12-31';
+----------+
| count(*) |
+----------+
|    15401 |
+----------+
1 row in set (0.02 sec)


mysql> describe select count(*) from date_test where  `d` between '2001-01-01' and '2001-12-31';
+----+-------------+-----------+-------+---------------+------+---------+------+-------+--------------------------+
| id | select_type | table     | type  | possible_keys | key  | key_len | ref  | rows  | Extra                    |
+----+-------------+-----------+-------+---------------+------+---------+------+-------+--------------------------+
|  1 | SIMPLE      | date_test | range | i             | i    | 4       | NULL | 30480 | Using where; Using index |
+----+-------------+-----------+-------+---------------+------+---------+------+-------+--------------------------+
1 row in set (0.00 sec)

mysql> describe select count(*) from date_test where YEAR(`d`) = 2001;
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+
| id | select_type | table     | type  | possible_keys | key  | key_len | ref  | rows   | Extra                    |
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+
|  1 | SIMPLE      | date_test | index | NULL          | i    | 4       | NULL | 762707 | Using where; Using index |
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+

mysql> describe select count(*) from date_test where `d` like "2001%";
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+
| id | select_type | table     | type  | possible_keys | key  | key_len | ref  | rows   | Extra                    |
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+
|  1 | SIMPLE      | date_test | index | i             | i    | 4       | NULL | 762707 | Using where; Using index |
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+
1 row in set, 1 warning (0.00 sec)


---
[upd] Как и ожидал between даёт эффект и при работе с or.
То есть поиск данных за определённый месяц тоже работает на ура, хотя выгода по времени уже не на столько заметна.

<?
$sql = "select count(*) from date_test where  ";
$tmp = array();
for ($i=1961; $i<=2011; $i++) {
$tmp[] = "`d` between '$i-01-01' and '$i-01-31'";
}
$sql .= join(" or ", $tmp);
?>

---

Преобразуется в длиннющий запрос:
select count(*) from date_test where  `d` between '1961-01-01' and '1961-01-31' or ... or `d` between '2011-01-01' and '2011-01-31

select count(*) from date_test where  `d` between '1961-01-01'....<откусил>
+----------+
| count(*) |
+----------+
|    64615 |
+----------+
1 row in set (0.45 sec)


mysql> describe select count(*) from date_test where  `d`...<откусил>
+----+-------------+-----------+-------+---------------+------+---------+------+-------+--------------------------+
| id | select_type | table     | type  | possible_keys | key  | key_len | ref  | rows  | Extra                    |
+----+-------------+-----------+-------+---------------+------+---------+------+-------+--------------------------+
|  1 | SIMPLE      | date_test | range | i             | i    | 4       | NULL | 64566 | Using where; Using index |
+----+-------------+-----------+-------+---------------+------+---------+------+-------+--------------------------+
1 row in set (0.00 sec)

mysql> select count(*) from date_test where d like __01%';
+----------+
| count(*) |
+----------+
|    64615 |
+----------+
1 row in set, 1 warning (0.92 sec)
mysql> describe select count(*) from date_test where d like __01%';
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+
| id | select_type | table     | type  | possible_keys | key  | key_len | ref  | rows   | Extra                    |
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+
|  1 | SIMPLE      | date_test | index | NULL          | i    | 4       | NULL | 762561 | Using where; Using index |
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+
1 row in set, 1 warning (0.00 sec)

---

В общем, не стоит отмахиваться от between ) реально удобно и быстро.
И, кстати, если внимательно приглядеться к выборке длиннющим запросом, то количество затрагиваемых тестами строк меньше чем количество результирующих строк. Сильно копошиться ломает, но предполагаю, что дело в бинарном поиске.
Ага, таки сильно ошибался я, а не Winer 02.03.11 00:31  
Автор: Fighter <Vladimir> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
Насколья помню - очень сильно ошибаешся. Нынешний мускул неоптимизирован только для OR 24.02.11 18:02  
Автор: Fighter <Vladimir> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
Это всё хорошо, но в Access'ом SQL'е данная комбинация не работает. 24.02.11 11:32  
Автор: Vedrus <Serokhvostov Anton> Статус: Member
<"чистая" ссылка> <обсуждение закрыто>
1  |  2 >>  »  




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2024 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach