Показать полную графическую версию : украшаем запрос MS SQL
1. можно ли как-то запустить Query Analyzer (2000) с ярлычка, чтоб он не заново запускался, а создал окошко в уже открытом аналайзере? А то задолбал плодиться, я забываю смотреть, есть он в живых или нет.
2. есть уже заполненная табличка:
declare @dates1 table (
recId integer, // прочая информация
groupId integer, // поле для группировки
dateIn datetime, // начало отрезка времени
dateOut datetime); // конец отрезка времени
нужно оставить в ней записи, имеющие хотя бы одно пересечение с другими при одинаковой groupId. Остальные удалить. Я сделал, но мне кажтся чёто как-то некрасиво и медленно, через delete where not exists(...). Сами понимаете, некрасивые самолёты не летают. Есть варианты как причесать запрос?
для MS SQL есть свой раздел форума
2. сразу сделать правильную (необходимую) выборку. Временные таблицы - очень ресурсоёмкое решение, так ли они нужны в данном случае?
для MS SQL есть свой раздел форума
Можно тему туда перенести? Я не заметил раздела
Может я неправильно понимаю как оно работает, обрисую задачу:
Есть табличка с оплаченными повременными услугами, примерно миллион-два записей (с 2004 года). Из них нужно выбрать такие записи за последние 4 недели, которые бы оплачивали одну и ту же услугу в одно и то же время, то есть выяснить какие есть перекрытия оплат.
Табличка имеет много всяких полей, я выбрал только нужные 4 поля за последние недели (около 1000 строчек), а потом искал пересечения
delete from
@dates
from
@dates debet1
where
not exists (
select * from @dates debet2
where
debet1.recId <> debet2.recId
and debet1.groupId = debet2.groupId
and debet1.dateIn < debet2.dateOut
and debet2.dateIn < debet1.dateOut);
А можно ли как-то создать временный view? чтобы съэкономить и упонятнить код
pva
1. Запускать скриптом, который проверяет наличие QA и либо запускает, либо активирует окно и отправляет комбинацию <Ctrl+N>
pva, я бы всё-таки работал с изначальной таблицей
где-то примерно так:
select groupId, дата, count (*)
from услуги
where дата>'2008-08-15'
group by groupId, дата
having count (*)>1
на выходе получаем список перекрытий
(в примере не понял соотношение dateIn и dateOut)
дело в том, что граница оказания услуг может быть и не кратна дню, пример:
услуга 1: от '2008-01-01 12:00:00' до '2008-01-02 14:00:00'
услуга 2: от '2008-01-01 18:00:00' до '2008-01-02 12:00:00'
т.е. имеем ряд временных диапазонов, нужно выбрать накладывающиеся? - да, группировкой тут не обойтись :-(
хотя всё равно не такой уж и монстрообразный запрос получается:
select u1.*
from
услуги u1, услуги u2
where
u1.dateIn>'2008-08-15' and u2.dateIn>'2008-08-15' -- 4 недели назад - лучше вынести в переменную
and u1.groupId=u2.groupId2 and u1.recId<>u2.recId
and (u1.dateIn beetwen u2.dateIn and u2.dateOut or u1.dateOut beetwen u2.dateIn and u2.dateOut)
Busla, Я приведу пример когда этот вариант не работает:
and (u1.dateIn beetwen u2.dateIn and u2.dateOut or u1.dateOut beetwen u2.dateIn and u2.dateOut)
.....время................
u1 1111111111111111111
u2 2222222222222
ни начало ни конец u1 не входят в u2.
теперь из каких соображений я делал:
u1 11111111111111
u2 222222222222222
1. если u2 начнётся после того, как u1 закончится - нет пересечения.
2. если u1 начнётся после того, как u2 закончится - нет пересечения.
3. иначе пересекаются.
упрощаем условие:
not (u2.dateOut <= u1.dateIn or u1.dateOut <= u2.dateIn) -->
--> u2.dateOut > u1.dateIn and u1.dateOut > u2.dateIn -->
--> u1.dateIn < u2.dateOut and u2.dateIn < u1.dateOut
Насчёт выборки действительно ступил - заработался. Всё действиетльно можно одним несложным селектом сделать. На сегодня такой вариант:
select
u1.recId,
u1.groupId,
u1.dateIn,
u1.dateOut
from
услуги u1
join услуги u2 on (
getDate() - 4*7 <= u2.dateIn
and u1.groupId = u2.groupId
and u1.dateIn < u2.dateOut
and u2.dateIn < u1.dateOut
and u1.recId <> u2.recId)
where
getDate() - 4*7 <= u1.dateIn;
order by
u1.groupId,
u1.dateIn
pva, всё правильно. Ты просто забываешь, что помимо
.....время................
u1 1111111111111111111
u2 2222222222222
будет и обратная пара:
u1 2222222222222
u2 1111111111111111111
не-а, не забываю :-P если список состоит только из этих двух записей, то твой вариант запроса выдаст только одну. А надо обе (это всё необходимо для отчёта, чтобы потом человек посмотел пересечения и принял решение, что из них поправить)
остаётся вопрос с временными view. Можно такие сделать? На сколько это критично к ресурсам? у меня услуги - это
accDebet join accCliPay on (accCliPay.accPayId=accDebet.accPayId and accCliPay.payCod=1)
Временные - это в том смысле, чтобы они уничтожались после выхода из блока, где были созданы, независимо от того успешно прошла операция или нет
Да, запрос у меня получился несколько однобокий.
AFAIK вьюхи интерпритируются примерно как макрос - т.е. хранится только код запроса, и он подставляется в другие запросы - содержимое view никак специально не индексируется, не кешируется и т.п.
Можно использовать не view, а подзапрос:
select *
from
(select * from accDebet join accCliPay on (accCliPay.accPayId=accDebet.accPayId and accCliPay.payCod=1)) as u1,
(select * from accDebet join accCliPay on (accCliPay.accPayId=accDebet.accPayId and accCliPay.payCod=1)) as u2
where
u1.dateIn>'2008-08-15' and u2.dateIn>'2008-08-15' -- 4 недели назад - лучше вынести в переменную
and u1.groupId=u2.groupId2 and u1.recId<>u2.recId
and u1.dateIn>=u2.dateIn and u1.dateIn<=u2.dateOut
так, по идее, в итоге каждая пара будет выдаваться один раз одной строкой (за исключением случая, когда dateIn у них идентичные - надо обрабатывать отдельно).
когда идентичные - это нормально, нужно обе выдавать. Вот теперь красиво получилось! Пасиба *DRINK*. Единственное, со знаком ">=" всё-таки надо строгое ограничение (без =), потому что если одна услуга заканчивается '2008-09-18 12:00' а другая начинается в это же время - это не пересечение
Временные - это в том смысле, чтобы они уничтожались после выхода из блока, где были созданы, независимо от того успешно прошла операция или нет »
Можно, но права администратора БД-нужны, (что не правильно в приложении).
View, с точки зрения программиста - SQL-запрос/макрос хранимый на стороне сервера. С точки зрения видимости - таблица БД.
Т. е. этакая виртуальная динамическая таблица.
Т. к. View практически ничего не занимают, то смысла Создавать-Удалять их в процессе выполнения нет никакого.
Более того, с точки зрения структурирования и изоляции кода это глупость.
Хочу заметить, что связка нескольких View в одном запросе читабельнее чем один сложный запрос с join.
Если вы хотите использовать конструкции управляемые в процессе выполнения, обратите внимание на хранимые процедуры.
Хочу заметить, что связка нескольких View в одном запросе читабельнее чем один сложный запрос с join. »
Поэтому и подумываю как бы тут view применить
Если вы хотите использовать конструкции управляемые в процессе выполнения, обратите внимание на хранимые процедуры. »
Рассматриваем только данный конкретный случай: нужно сказать серверу что я собираюсь сделать 2 раза одинаковый запрос и соединить его. Оставлять view навека в базе не хочется. Всё-таки временную таблицу (declare @t1 table...) сделать?
Оставлять view навека в базе не хочется »
А почему собственно? Они для этого и предназначены.
Всё-таки временную таблицу (declare @t1 table...) сделать? »
Временная таблица, ( т. е. та которая существует только во время сессии - я правильно вспомнил терминологию MS SQL? Давно не работал с ним.)
Тоже не плохой выход, особенно с точки зрения, работы с высоконагруженными базами.
Наверно, самый оптимальный случай особенно при очень сложных выборках.
С точки зрения блокировок, "монолитный" запрос это самое печальное.
Временная таблица, ( т. е. та которая существует только во время сессии - я правильно вспомнил терминологию MS SQL? »на самом деле pva путает понятия временная локальная таблица и таблица-переменная. Он использует таблицу-переменную. Суть, впрочем, та же - автоматически удаляется с закрытием сессии.
Тоже не плохой выход, особенно с точки зрения, работы с высоконагруженными базами. »очень спорно - выборка по данным та же, но временную таблицу ещё надо где-то хранить и строить к ней свои индексы. В данном случае - совершенно неэффективно.
но временную таблицу ещё надо где-то хранить и строить к ней свои индексы. »
"Быстро, качественно, недорого. Выберите любые два пункта!"
Естественно придется жертвовать памятью ради скорости, либо наоборот.
Что касаемо индексов. Вроде бы человек туда уже агрегированные данные собирается выгружать?
Если же нет, то вы правы, когда размер временной таблицы соизмерим с основной, то смысла это не имеет.
Однако, повторюсь:
1) Лично я бы работал с View.
2) С MS SQL не работал давно, за сим мои мысли о проиводительности можно опустить, как ламерские :)
Цитата pva:
Оставлять view навека в базе не хочется »
А почему собственно? Они для этого и предназначены. »
Потому что view типа "показать данные за 4 недели" несёт смысловую нагрузку только для данного конкретного запроса, который выполняется раз в месяц. Нужен он только для того, чтобы сказать серверу, что я собираюсь сделать 2 раза одинаковую выборку. Если бы это была наполненная смыслом выборка хотя бы для нескольких отчётов, я бы сделал view без вопросов.
на самом деле pva путает понятия временная локальная таблица и таблица-переменная »
каюсь! мне нужно то, (не знаю как оно правильно называется) что самоуничтожится как автоматическая переменная в с++
pva,
Может быть имеет смысл применить функции пользователя (http://www.intuit.ru/department/database/sql/11/) ?
Будете передавать в нее две переменных (временной диапазон), получать таблицу.
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.