Тренинг по MS SQL Server
Имеется 2 таблицы: tbl1 & tbl2
tbl1 -> _PrimaryKey, brand_name .....
tbl2 -> _ForeignKey, product_name ...
связь один ко многим по ключам. для одного бренда может быть несколько полей с разными _PrimaryKey (как id товара, например)
задача: подсчитать кол-во товара из tbl2 для бренда 'ааа'.
решение:
FROM tbl2
WHERE _ForeignKey IN (
SELECT _PrimaryKey FROM tbl1 WHERE brand_name = 'aaa');
FROM tbl2 JOIN tbl1 ON _ForeignKey = _PrimaryKey
WHERE brand_name = 'aaa';
from tbl2 t2
join tbl1 t1 on t1._PrimaryKey = t2._ForeignKey
where t1.brand_name = 'aaa'
Прежде всего, лучше сразу указывать версию сервера, от этого может варьироваться разнообразие решений. Версию можно получить выполнив запрос select @@version.
По поводу того как выполняется запрос. В sql server есть такой модуль как оптимизатор запросов. Он отвечает за то, как ваш логический запрос будет приведен в последовательность физических действий. Т.е. вы пишете select * from mytable, а оптимизатор решает какие именно физические операции нужно сделать чтобы получить результат. То в какой последовательности и как будет выполнять сервер называется планом запроса. Вы можете просматривать план запроса при помощи
1) графической среды выполнения запросов (если 2000, то Query Analyzer(QA), если 2005 и выше Sql Server Management Studio (SSMS).
2) перед запросом перевести контекст выполнения в особый режим одной из следующих инструкций
set showplan_all on или set showplan_text on или set showplan_xml on
выключить режим можно указав вместо on параметр off.
Касательно вашего запроса, в приложенном файле как раз скрин графического плана этого запроса из SSMS.
Теперь как читать план и что означают пиктограммы. План читается справа налево и представляет собой дерево, каждый узел которого это оператор работы с данными, физический или логический. Корневой вершиной собственно является узел на котором был получен конечный результат. Если навести мышкой на узел откроется окошко с подробностями про оператор который представлен в этом узле.
Впринципе тут можно долго распинаться, но по сути это будет только пересказ msdn, так что просто дам ссылки.
Справочник по логическим и физическим операторам
Графическое отображение планов выполнения (SQL Server Management Studio)
Анализ запроса
Касательно привденного плана вышего запроса. Читаем справа налево чтопроисходит.
Сканирование всех строк таблицы @tbl1, причем заметьте в подробностях указано predicate brand_name = 'aaa', это значит он сканирует встроки таблицы и отбирает только те которые удовлетворяют условию в where. Т.е. уже видно что немного не так как вы предполагали, условие отрабатывает до соединения таблиц.
Далее сканируется вторая таблица.
После этого выполняет соединение. слово Hash обозначает алгоритм по которому соединяются строки.
После этого выполняется агррегирвоание строк (функция count)
Потом полученный скаляр выводится в результат.
Результат получился правильный. Отсюда следующий совет, когда говорите что что-то не праильно, приводите либо текст ошибки, либо описание какие нужны результаты, а какие получены.
А чтобы другие могли воспроизвести у себя эти результаты желательно приводить скрипты по созданию и заполнению тестовых табличек и сам запрос. Вот например, я тестировал на этих данных:
-- для нас тут важно то, что она уничтожается после выполнения запроса,
-- по этому она хорошо подходит в качестве таблички для проверки запроса
declare @tbl1 table(_PrimaryKey int identity, brand_name varchar(100))
declare @tbl2 table(_ForeignKey int, product_name varchar(100))
-- эта часть заполняет таблицы тестовыми занными
insert into @tbl1 select 'aaa' union all select 'bbb' union all select 'ccc'
insert into @tbl2 select 1, 'a-product1' union all select 1, 'a-product2' union all select 1, 'a-product3'
union all select 2, 'b-product1' union all select 2, 'b-product2' union all select 3, 'c-product1'
-- это собственно ваш запрос
SELECT count(_ForeignKey)
FROM @tbl2 JOIN @tbl1 ON _ForeignKey = _PrimaryKey
WHERE brand_name = 'aaa';
-- результат его выполнения
-- 3
-- т.е. вроде правильный результат.
------------------------------------
Microsoft SQL Server 2005 - 9.00.5000.00 (Intel X86)
Dec 10 2010 10:56:29
Copyright (c) 1988-2005 Microsoft Corporation
Standard Edition on Windows NT 5.2 (Build 3790: Service Pack 2)
Следование этим советам позвоит мне и другим участникам форума более точно отвечать на ваши вопросы. Так что дерзайте и если не плюнете на все это дело, то постараемся разъяснить все моменты =)
SomewherSomehow, спасибо за подробный ответ, много интересного ) замечания учту. насчет мне надоест, скорее я еще надоем, и самой себе в том числе ) а учить язык все равно придется, выбора нет.
насчет того что ни привела подробностей, это задача с сайта где запрещено их задачи обсуждать на стороннем форуме, вот я и описала аналог своими словами без подробностей, СУБД прямо у них на сайте интегрирована для решения их задач:
сайт хороший, но подобные вещи меня ставят в тупик, когда на мой взгляд запрос должен работать, у них выдает ошибку что не правильно... - у меня крышу рвет, начинаю чувствовать, что у меня серьезные проблемы :mad: просто на ощупь сделать запрос, что то убавить, добавить, посмотреть их хелп и т.д. - вполне возможно, но меня такой слепой метод не устраивает, мне всегда важно понимать причину и следствие, иначе это не учеба, а пустая трата времени - дорогое удовольствие. поэтому постараюсь разобраться с этими проблемами, т.к. время они у меня забирают очень много. первое - надо будет на своем компе установить ms sql, а то конечно не очень удобно получается.
моя цель сейчас базис повторить/выучить (около 5 лет назад учила Oracle):
1. запросы разных уровней сложности
2. использование переменных
3. хранимые процедуры
- ..... по пути наверно еще обнаружиться, что мне надо )
мой выбор ms sql - самая популярная, востребованная СУБД у нас на рынке, затем MySql. Oracle - иногда требуется, часто как дополнение к мс скл... в общем живем по потребностям )
Если кроме мсдн вы еще можете посоветовать мне хорошие книги, сайты, связанные с теорией СУБД (построение таблиц, связи и т.д.), настройки(хотя подозреваю что тут мсдн рулит), сборник задач и т.д. - буду благодарна.
Ну, во-первых с алиасами действительно удобнее, а во-вторых, когда запрос выглядит вроде как правильно, почему бы не достать бубен?:)
да потому что я учусь :) а танцы с бубнами этому не помогают )
а так, конечно я могу и беру бубен, но это не решает проблемы, как я писала выше.
Насчет книг, мое имхо, что субд какого-либо производителя лучше изучать по книгам этого производителя. MSDN хорош, но как самоучитель не очень подходит, тут тоже понимаю вас, ибо все-таки это прежде всего документация и стиль изложения соответствующий.
Я вам рекомендую прежде всего книгу самой microsoft называется "Microsoft Corporation Проектирование и реализация баз данных Microsoft SQL Server 2000. Учебный курс". (есть кстати в пдф-ке у меня 46 м.б. могу отправить если влезет в почту, но в инете и так легко гуглится). Поищите может есть такая же и по 2005 в электронном виде, я не искал. Книга построена ввиде самоучителя для подготовки к экзамену, так что если найдете про 2005 можете потом и на сертификатик сдать экзамен (по 2000 экзамены уже отменены). Хотя основы что для 2000, что для 2005 - одинаковы, так можно читать не напрягаясь, практически все написанное там применимо и к более новым версиям.
Есть более современные книги " Разработка приложений на основе Microsoft SQL Server 2005. Авторы Эндрю Дж.Браст, Стивен Форте"., "Microsoft SQL Server 2005 Справочник администратора. Уильям Станек." - это тоже книги редакции MS Press, так что рекомендую.
Еще порекомендую после основ найти и почтить книги Кена Хендерсона. Но там уже рассчитано на имеющих опыт, описываются всякие низкоуровневые вещи, на первых порах точно не надо.
Насчет задачек с примерами, вы похоже уже нашли то что я хотел порекомендовать =) Так что я кажется понимаю о каком сайте вы говорите. =)
Относительно этой задачи, честно говоря фиг знает, что там было в первоначальном условии, но в том условии как вы написали, вариант с join 100% правильный, даже не знаю что бы такое придумать, чтобы его сломать... Может чего не дописали и есть какие-то еще требования или условия? Попробую подумать еще.
Кстати я насколько помню на том сайте ошибка как-то диагностируется, типа вернулось больше рядов или меньше рядов или еще что-то...
думаю тяжело будет думать не видя источника проблемы. лучше я попробую найти страницу, откуда я эту задачу раскопала и кинуть ссылку на их источник, насколько я помню, это из туториала(примеры выборки из нескольких таблиц):
http://www.sql-tutorial.ru/
я вчера у них на 16 задаче поехала ) вот и заехала, уже не помню что откуда и куда. сейчас поискала - не нашла, будет время там позаниматься, думаю дня через 2-3, может опять найду, где я эту задачу нашла.
спасибо за рекомндации, все учту, погуглю ;-) хотя почта думаю файл приняла бы, но по любому буду проверять книгу на наличие более поздней версии бд.
declare @tbl2 table(_ForeignKey int, product_name varchar(100))
-- эта часть заполняет таблицы тестовыми занными
insert into @tbl1 select 1, 'aaa' union all select 2, 'bbb' union all select 3, 'ccc'
insert into @tbl2 select 1, 'a-product1' union all select 1, 'a-product2' union all select 1, 'a-product3'
union all select 2, 'b-product1' union all select 2, 'b-product2' union all select 3, 'c-product1'
-- 1
SELECT count(*)
FROM @tbl2 JOIN @tbl1 ON _ForeignKey = _PrimaryKey
WHERE brand_name = 'aaa';
-- 2
SELECT count(*)
FROM @tbl2
WHERE _ForeignKey IN (SELECT _PrimaryKey FROM @tbl1 WHERE brand_name = 'aaa');
план в файле, видно что оптимизатор все это приводит к единому набору операторов, и выполняться они будут одинаково и всегда приводить к одним результатм.
но это при условии если в первой таблице поле _PrimaryKey будет действительно первичным ключем, т.е. скрипт создания таблицы такой: declare @tbl1 table(_PrimaryKey int primary key, brand_name varchar(100)). Это заставляет оптимизатор предположить, что повторяющихся значений там быть не может и он приводит второй запрос к такому же плану с Inner join что логично.
Но если таблицу создать без первичного ключа вот так: declare @tbl1 table(_PrimaryKey int, brand_name varchar(100)), планы буду естественно разные. И тогда если в этом поле возможны повторяющиеся значения, то запрос с джойном сломается. Вот например,
declare @tbl2 table(_ForeignKey int, product_name varchar(100))
-- эта часть заполняет таблицы тестовыми занными (которые сломают запрос)
insert into @tbl1 select 1, 'aaa' union all select 1, 'aaa' union all select 2, 'bbb' union all select 3, 'ccc'
insert into @tbl2 select 1, 'a-product1' union all select 1, 'a-product2' union all select 1, 'a-product3'
union all select 2, 'b-product1' union all select 2, 'b-product2' union all select 3, 'c-product1'
SELECT count(_ForeignKey)
FROM @tbl2 JOIN @tbl1 ON _ForeignKey = _PrimaryKey
WHERE brand_name = 'aaa';
SELECT count(*)
FROM @tbl2
WHERE _ForeignKey IN (SELECT _PrimaryKey FROM @tbl1 WHERE brand_name = 'aaa');
разультаты 6 и 3 соответсвенно. В связи с этим вопрос, то что вы назвали в первой таблице полем _PrimaryKey - действительно представяет собой Primary Key или там все же есть повторяющиеся значения? Если есть, то ответ на ваш вопрос найден, если же это рельно первичный ключ, то запросы 100% одинаковые, по крайней мере в тех условиях что вы дали.
И да, поставьте mssql на машину за которой работаете, легче будет изучать и понимать, сразу скопипастил запрос - сам все увидел. Если проблемы с покупкой лицензии, то есть express версия, она бесплатна, а позволяет делать очень многое. Только по-моему к ней нет графических инструментов, но и это решаемо впринцпе =)
Насчет почты, можете попробовать отсюда скачать (кстати на сайте еще много интересных книг и по бд и вообще). Если не получится, то кидайте адрес в личку, попробую отправить.
Насчет почты, можете попробовать отсюда скачать (кстати на сайте еще много интересных книг и по бд и вообще). Если не получится, то кидайте адрес в личку, попробую отправить.
один и тот же сайт, та книга, ссылку на которую я дала, это их дополнительный учебник, в том числе используется как Хелп.
да, задача ихняя, только я по моему ее выловила с туториала. сонная была, уже точно не помню.
вот структура БД:
http://www.sql-ex.ru/help/select13.php
речь о Computer firm
надо было подсчитать кол-во товара в таблице PC для maker 'A'. Один и тот же производитель может иметь продукцию ПК, Лаптопы, Принтеры.
только чтобы не забанили меня) хотя задача не рейтинговая, но сайт мне в общем нравиться, но если там действительно подвохи, они мне очень дорого обошлись, время и так не много, а я вместо учиться - расстроилась) думала быстро пройду этот самоучитель(действительно хоть базу срочно надо заложить), а тут такое.
п.с. а на "ты" можно? как то в Израиле отвыкла, да и в силу возраста не успела особо привыкнуть :) имею ввиду время проживания вне Израиля, сейчас то уже посолидней =)
Спасибо за ссылку, гляну. Кстати, немного стало легче, что не только я думаю, что запросы одинаковы ) давно не практикавалась, стала понемногу возвращаться в программинг и переживаю, что я уже не та, но все же вроде голова на месте, хотя конечно бывает всякое.
Насчет банов - хз, я видел несколько раз обсуждения не рейтинговых задач на других форумах, не знаю, забанили там кого-нить или нет =)
Посмотрел схему, если под tbl1 подразумевалась таблица Продукт, под tbl2 таблица ПК, а под ключевым полем по которому организована связь поле модель, то все правильно, запрос с джойном работает. Единственное нужно указать еще дополнительно в условии соединения что из таблицы продукт требуются записи только с типом ПК, т.к. в этой таблице хранятся сведения моделей и других устройств, лэптопов и принтеров.
В точности такой же задачки не нашел. Но вот например найти среднюю скорость ПК выпущенных фирмой А - получилось именно таким способом.
правильно, но это если разобралась )
Насчет банов - хз, я видел несколько раз обсуждения не рейтинговых задач на других форумах, не знаю, забанили там кого-нить или нет =)
ну, меня предупредили, что могут, а подробностей я не знаю.
Посмотрел схему, если под tbl1 подразумевалась таблица Продукт, под tbl2 таблица ПК, а под ключевым полем по которому организована связь поле модель, то все правильно, запрос с джойном работает.
именно так.
да, это было учтено. видно я упростила условие, когда сюда пример делала. написала только самое наболевшее )
В точности такой же задачки не нашел. Но вот например найти среднюю скорость ПК выпущенных фирмой А - получилось именно таким способом.
задача вроде с туториала, я тоже не нашла, пока. если найду, заброшу сюда.
спасибо за помощь)