Хранилища данных Методические рекомендации для выполнения практических заданий Казань – 2013



Скачать 375.57 Kb.
страница 1/2
Дата 30.08.2016
Размер 375.57 Kb.
  1   2


КАЗАНСКИЙ (ПРИВОЛЖСКИЙ) ФЕДЕРАЛЬНЫЙ УНИВЕРСИТЕТ

Пинягина О.В.
Хранилища

данных

Методические

рекомендации

для выполнения

практических заданий

Казань – 2013

Оглавление




Оглавление 2

Работа в программе SQL Server 3

Этап 1: Описание предметной области, разработка модели, создание таблиц. 3

Этап 2. Заполнение базы данными. 7

Этап 3. Запросы, представления, а также хранимые процедуры. 15

Этап 4. ETL – extract, transform, load (извлечь, преобразовать, загрузить). 21

Этап 5. ETL – extract, transform, load (извлечь, преобразовать, загрузить). 25



Работа в программе Deductor Studio 29

Этап 6а: Загрузка данных в Deductor Studio из текстовых файлов, создание хранилища данных в СУБД FireBird. 29

Этап 6б: Преобразования и визуализаторы. 43

Этап 7. Применение методов Data Mining. 61



Литература 68


Работа в программе SQL Server


Этап 1: Описание предметной области, разработка модели, создание таблиц.

Постановка задачи:

В базе данных «Аптеки» накапливается оперативная информация по реализации лекарств и других товаров через аптечную сеть, состоящую из нескольких аптек. Каждый товар имеет фирму-производителя, тип, вид фасовки, текущую цену. В один чек может быть внесено несколько товаров. В зависимости от общей суммы покупки делается скидка по следующему правилу: от 1000 до 5000 р. – 2%, более 5000 р. – 5%.

По мере накопления оперативной информации возникает необходимость её анализа. У пользователей появляются вопросы:

- Сколько единиц каждого товара и на какую сумму продано в каждой аптеке?

- Сколько единиц каждого типа товаров и на какую сумму продано

в каждой аптеке?

- На какую сумму продано лекарств «от гриппа» в каждой аптеке в порядке убывания итоговой суммы?

- А можно получить суммы продаж «от гриппа» по месяцам в порядке убывания итогов?

- А если по каждой аптеке отдельно?

- А сколько реализовано товара с названием «Товар 117» в «Аптеке 10» за август текущего года?

- А можно получить такую таблицу, чтобы столбцами были, например, месяцы, а в строках находились типы товаров и итоги продаж по месяцам?

- А можно построить графики или диаграммы для продаж за текущий год? А по отдельному товару? А сразу по нескольким товарам, для сравения?

- А можно построить прогноз продаж на следующий месяц?

И т.п.

Начнем реализацию задачи с построения ER-модели:



Для этой базы данных используется модель «Снежинка», центральным объектом (фактами) является «Продажа», представляющая собой слабую сущность, которая зависит от сущностей (измерений) «Чек», «Товар» и «Аптека». В свою очередь, сущность «Товар» ссылается на измерения «Фирму-производителя» и «Тип товара».

В модели «Снежинка» всегда имеется некоторая сущность (факты), которая является центром, от нее исходят лучи к сущностям следующего уровня (измерениям), от которых также могут исходить лучи к сущностям третьего уровня (измерениям), и т.п. – получается структура, отдаленно напоминающая снежинку:





Структура «Звезда» проще: здесь есть только центр (факты) и лучи, указывающие на один уровень измерений:



Далее следует написать сценарий создания таблиц базы данных на языке SQL и выполнить его в среде SQL server management studio. Рекомендуется для названия баз данных, таблиц, столбцов и т.п. не использовать русские буквы.

После создания базы данных проведем «обратное проектирование» - создадим в SQL server диаграмму базы данных:

Убедимся, что полученная картинка по структуре соответствует нашей ER-модели.

Задание 1. Выберите предметную область, подходящую для разработки хранилища данных. Примерная схема: оперативная информация хранится в слабой сущности, плюс 3 или более сильных сущности (модель «звезда»), либо ещё плюс справочники (модель «снежинка») (5 баллов). Создайте таблицы в SQL Server. После создания БД проведите «reverse engineering» - создайте диаграмму базы данных с помощью автоматизированных средств SQL Server (2 балла). ER-модель сдавать не обязательно, достаточно диаграммы из SQL Server. (Итого 7 баллов)

Этап 2. Заполнение базы данными.

Реальные данные в масштабах тысяч записей нам взять негде. Поэтому будем генерировать их искусственно. Следует сгенерировать не менее 1000 записей для оперативных данных и по 10-100 для остальных таблиц. Можно использовать хранимые процедуры, а также загружать данные из внешних источников. Рассмотрим все эти возможности.

Пример реализации:

Таблицу «Тип» заполним вручную:

SELECT * FROM Type



Для заполнения таблицы «Фирма» разработаем хранимую процедуру, которая создает 20 строк примерно такого вида:




CREATE PROC insert_firms AS

DECLARE @nom INT

SET @nom=1

WHILE @nom

BEGIN

INSERT INTO Firm (NumFirm, NameFirm)



VALUES (@nom, 'Фирма '+LTRIM(STR(@nom)))

SET @nom=@nom+1

END

Для заполнения таблицы «Аптека» разработаем хранимую процедуру, которая создает 20 строк примерно такого вида:



Здесь поле «Телефон» заполнено псевдослучайными равномерно распределенными числами в диапазоне от 100000 до 999999. Для этого используется функция RAND(), которая возвращает значение с плавающей точкой, равномерно распределенное от 0 до 1. Для того чтобы эта функция в рамках процедуры всегда генерировала один и тот же набор случайных чисел, следует ее предварительно вызвать с параметром-константой, например: SET @x=RAND(1)

Итак, функция RAND возвращает случайное значение из отрезка [0, 1]. Для того чтобы получить, например, значение из отрезка [100, 150], следует умножить полученную величину на 50 (длина отрезка) и прибавить 100 (левый конец отрезка).

Для преобразования чисел с плавающей точкой к целому типу удобно использовать функцию CEILING (это «потолок» по-русски), которая преобразует свой аргумент к ближайшему большему целому числу. Есть также симметричная ей функция FLOOR, которая преобразует аргумент к ближайшему меньшему целому числу.

Для заполнения таблицы «Товар» разработаем хранимую процедуру, которая создает 210 строк примерно такого вида:

Здесь поле «НомерФирмы» заполнено псевдослучайными равномерно распределенными числами в диапазоне первичного ключа таблицы «Фирма». Поле «Номер типа» заполнено такими значениями: товар1-товар30 относится к типу1, товар31-60 относится к типу2 и т.п., товар181-210 относится к типу7.

Для заполнения поля «Цена» мы используем более сложное правило: 50 % лекарств имеет цену от 0 до 200 р., и 50 % - от 200 до 3000 р.

Для заполнения таблицы «Чек» разработаем хранимую процедуру, с помощью которой создадим 12000 строк примерно такого вида:



Здесь дата генерируется следующим образом. Для того чтобы проиллюстрировать увеличение объема продаж, создадим 3500 чеков за 2010 год, 4000 – за 2011 год и 4500 – за 2012 год. Будем генерировать месяц по следующему правилу: 30% продаж приходится на зиму, а остальное – поровну на весну, лето и осень. С учетом этого правила сгенерируем номер месяца.

Номер дня также выбирается случайно, с учетом количества дней в полученном месяце. Затем из этих частей составляется дата в виде строковой переменной в формате ‘ГГГГ-ММ-ДД’. Время – часы, минуты, секунды – тоже можно при необходимости генерировать случайным образом. Поле «Скидка» будет заполнено позже, когда будут данные о продажах.

Наконец, заполним таблицу «Продажа».



Для заполнения этой таблицы создадим хранимую процедуру, которая перебирает все строки из таблицы «Чек» (вспомните о возможности использования курсоров!). Предполагаем, что в каждом чеке может быть от 1 до 5 наименований лекарств, каждое в количестве от 1 до 2 штук. Цена лекарства копируется из таблицы «Товар», позже по сумме чека будем вычислять скидки. Для того чтобы отразить сезонность продаж разных типов лекарств, используем следующие правила:



  • зимой 50% проданных лекарств относятся к типу "от гриппа", остальные типы равновероятны,

  • весной 50% проданных лекарств относятся к типу "витамины", остальные типы равновероятны,

  • летом 50% проданных лекарств относятся к типу "против диареи", остальные типы равновероятны,

  • осенью 50% проданных лекарств относятся к типу "от кашля", остальные типы равновероятны.

Создано более 35 тыс. строк, процедура выполнялась около 4 минут! – что-то слишком медленно, похоже, следует проанализировать узкие места процедуры.

Узкими местами обычно бывают условия в запросах. Выполнение запросов можно существенно ускорить, если применять индексы. В нашей процедуре используется запрос к таблице sale с условием на поле numCheck, по которому в данной таблице нет индекса. Создадим его:

CREATE INDEX saleCheck ON sale (numCheck)

Снова запустим ту же самую процедуру. Теперь она выполнилась за 18 секунд!

Теперь напишем процедуру для вычисления скидок (это необязательный этап, просто для данной предметной области он позволяет придать нашим искусственным данным больше правдоподобия). Обратите внимание на использование конструкции CASE

CREATE PROC Discounts AS
DECLARE cur1 CURSOR FOR SELECT NumCheck FROM Bill

DECLARE @numCheck NUMERIC(6),

@sumCheck NUMERIC(6),

@coeff INT


OPEN cur1

FETCH cur1 INTO @numCheck

WHILE @@FETCH_STATUS=0

BEGIN


-- считаем сумму чека и процент скидки

SELECT @sumCheck=SUM(price*quantity), @coeff=

(CASE

WHEN @sumCheck>5000 THEN 5



WHEN @sumCheck>1000 AND @sumCheck

ELSE 0


END)

FROM sale WHERE @numCheck=numCheck

-- записываем скидку в чек

UPDATE Bill SET Discount=@coeff WHERE @numCheck=numCheck

-- уменьшаем цену в продажах на процент скидки

UPDATE Sale SET Price=Price*(100.0-@coeff)/100.0

WHERE @numCheck=numCheck

FETCH cur1 INTO @numCheck

END

DEALLOCATE cur1



Таблицы «Чек» и «Продажа» после выполнения процедуры подсчета скидок:

Наконец, проиллюстрируем загрузку данных из внешнего текстового файла. Пусть для аналитических целей, кроме рассмотренных выше данных о продажах, нам понадобится информация о лекарствах, которые выдавались пациентам-льготникам бесплатно. Эту информацию мы сгенерируем, например, с помощью программы, написанной на C#.

В созданном файле данные хранятся в формате:

Номер; ФИО; паспорт; лекарство; дата; количество

Петров Семен Михайлович;6917670044;Товар 87;2012-05-30;1

Иванов Сидор Алексеевич;9907904329;Товар 136;2012-08-09;2

Гусев Роман Петрович;2448164671;Товар 76;2012-10-06;2

Грачев Олег Сергеевич;7450606066;Товар 140;2012-01-31;2

Петров Сергей Сергеевич;3455426424;Товар 199;2012-09-12;1

Гусев Семен Сидорович;4181356995;Товар 105;2012-03-11;2

Петров Роман Петрович;9762907822;Товар 98;2012-08-02;1

Петров Алексей Сергеевич;3758461561;Товар 200;2012-11-24;1

Сидоров Семен Романович;4620556475;Товар 155;2012-12-04;1

Петров Семен Алексеевич;4481875260;Товар 74;2012-01-20;2

и т.п.

Обратите внимание, что в формате даты день и месяц обязательно должен состоять из двух цифр!



Создаем таблицу с такой же структурой. Чтобы проще было копировать данные, порядок полей сделаем в точности таким же, как в файле:

CREATE TABLE SocialReceipt

( fioCust VARCHAR(100) NOT NULL,

pasportCust VARCHAR(10) NOT NULL,

nameArticle VARCHAR(20) NOT NULL,

dateCust DATETIME NOT NULL,

quantityCust INT NOT NULL)
Для загрузки данных из внешнего источника в SQL server существуют разные способы. Мы воспользуемся программой bcp (bulk copy procedure – процедура массового копирования). Эта программа служит как для загрузки данных из текстового файла, так и для выгрузки данных в текстовый файл.

Программа bcp запускается из командной строки Windows (Пуск – Выполнить – cmd OK ). В нашем случае формат команды следующий:



bcp drugstores.dbo.SocialReceipt in c:\customers.txt -T -S HOME\SQLEXPRESS -C 1251 -t; -c

Здесь drugstores.dbo.SocialReceipt - полное имя таблицы данных, в которую мы загружаем информацию, в виде: ИмяБД.Владелец.ИмяТаблицы;

in – направление потока данных: извне в SQL server;

c:\customers.txt – полное имя файла-источника;

-T – флажок означает, что используется тип аутентификации Windows, т.е. операция выполняется от имени пользователя Windows;

-S HOME\SQLEXPRESS – имя SQL-сервера;

-C 1251 – флажок задает кодовую страницу для правильного отображения русских букв (в программе на C# при создании файла нужно задать ту же кодовую страницу, например, через Encoding.GetEncoding(1251) );

-t; - флажок задает в качестве символа-разделителя полей “;”

-c – флажок указывает, что на входе предполагаются данные в символьном (текстовом) представлении. При использовании этого параметра не запрашивается тип данных каждого поля.

Запустим программу на выполнение:



Теперь таблица льготников успешно заполнена:



Задание 2 . Следует сгенерировать не менее 1000 записей для оперативных данных и по 10-100 для остальных таблиц. Можно использовать хранимые процедуры (если основные таблицы заполнены с помощью хранимых процедур, то 5 баллов; если при этом данные генерируются с учетом вероятностей (частот), то еще плюс 5 баллов). Можно сгенерировать данные с помощью внешней программы (написанной, например, на С#) и записать их в текстовый файл, а затем загрузить в базу (если таблица с оперативной информацией загружена из файла, то ещё плюс 5 баллов). В самом крайнем случае, можно ограничиться максимум сотней строк для каждой таблицы и все данные занести вручную (1 балл). (Итого 15 баллов)

Этап 3. Запросы, представления, а также хранимые процедуры.

Пример реализации:

Для начала напишем сложный запрос, который содержит детальную информацию о продажах: какие товары, в каком количестве, каких типов, каких фирм, какие аптеки и когда продали:

SELECT NameArticle, s.Price, NameType, NameFirm, Address, DateCheck,

b.NumCheck, Quantity

FROM Bill b, Drugstore d, Firm f, Article a, Sale s, Type t

WHERE

b.numCheck=s.numCheck AND



d.numDrug=s.numDrug AND

t.numType=a.numType AND

a.numArticle=s.numArticle AND

f.numFirm=a.numFirm

а ещё лучше сформулировать вот так (запрос имеет более чёткую структуру, никакое условие связи не потеряется):

SELECT NameArticle, s.Price, NameType, NameFirm, Address, DateCheck,

NumCheck, Quantity

FROM Sale s JOIN Article a ON a.numArticle=s.numArticle

JOIN Bill b ON b.numCheck=s.numCheck

JOIN Drugstore d ON d.numDrug=s.numDrug

JOIN Firm f ON f.numFirm=a.numFirm

JOIN Type t ON t.numType=a.numType



Если мы хотим сохранить этот запрос для дальнейшего использования, можно создать представление:

CREATE VIEW fullSalesView AS

SELECT NameArticle, NameType, s.Price, NameFirm, Address, DateCheck, b.NumCheck, Quantity

FROM Sale s JOIN Article a ON a.numArticle=s.numArticle

JOIN Bill b ON b.numCheck=s.numCheck

JOIN Drugstore d ON d.numDrug=s.numDrug

JOIN Firm f ON f.numFirm=a.numFirm

JOIN Type t ON t.numType=a.numType

А также можно создать вспомогательную таблицу и переписать данные в неё:

CREATE TABLE fullSalesTable

(

NameArticle VARCHAR(50),



NameType VARCHAR(50),

Price Numeric(6,2),

NameFirm VARCHAR(50),

Address VARCHAR(50),

DateCheck DATETIME,

NumCheck INT,

Quantity INT,

CONSTRAINT pk_sales PRIMARY KEY(NameArticle, Address, NumCheck)

)
INSERT INTO fullSalesTable SELECT * FROM fullSalesView

Обратите внимание, что данная таблица денормализована (первичным ключом можно считать комбинацию из названия товара, аптеки и номера чека). Из названия товара (части ключа) следует название фирмы и тип лекарства (неключевые поля), а из номера чека следует дата чека, то есть, нарушена вторая нормальная форма.

Таблица или представление, которые мы только что получили, на самом деле хранят многомерные данные. Многомерные данные удобно представлять в виде так называемых OLAP-кубов.

На следующем рисунке представлен OLAP-куб для нашей таблицы. Каждая ячейка такого куба хранит количество и цену некоторого товара, проданного в некоторой аптеке в составе некоторого чека. «Количество» и «Цена» представляют собой факты куба, а «Товар», «Аптека» и «Чек» - измерения куба. Заметим, что измерение «Товар» может быть сгруппировано (или агрегировано) по типу товара или по фирме-изготовителю, а измерение «Чек» может быть агрегировано по дате, или по месяцу, или по году.

Из этого куба можно получать отдельные ячейки, срезы, а также агрегировать данные по разным критериям.

Рассмотрим разные запросы с агрегированием данных, т.е., с использованием группировок и итоговых функций.

- Сколько единиц каждого товара и на какую сумму продано в каждой аптеке?
SELECT NameArticle, Address, SUM(Quantity), SUM(Quantity*Price)

FROM fullSalesView

GROUP BY NameArticle, Address

В этом примере мы «схлопнули» (просуммировали) измерение «Чек», а по остальным измерениям оставили текущий уровень детализации.


- Сколько единиц каждого типа товаров и на какую сумму продано

в каждой аптеке?


SELECT NameType, Address, SUM(Quantity),SUM(Quantity*Price)

FROM fullSalesView

GROUP BY NameType, Address

А в этом примере мы также «схлопнули» измерение «Чек», а для измерения «Товар» произвели агрегирование по типу товара.


- На какую сумму продано лекарств «от гриппа» в каждой аптеке в порядке убывания итоговой суммы?
SELECT Address, SUM(Quantity*Price) FROM fullSalesView

WHERE NameType='против гриппа'

GROUP BY Address

ORDER BY 2 DESC



В этом случае мы получили срез куба – в измерении «Товар» мы зафиксировали значение для типа товара. По измерению «Аптека» уровень детализации остался исходным, по измерению «Чек» все значения просуммированы.


- А можно получить суммы продаж «от гриппа» по месяцам в порядке убывания итогов?
SELECT MONTH(DateCheck), SUM(Quantity*Price) FROM fullSalesView

GROUP BY MONTH(DateCheck)

ORDER BY 2 DESC

В этом случае мы также получили срез куба – в измерении «Товар» мы зафиксировали значение для типа товара. По измерению «Аптека» все значения просуммированы, а по измерению «Чек» данные агрегированы в масштабе месяцев.
- А если по каждой аптеке отдельно?
SELECT Address, MONTH(DateCheck), SUM(Quantity*Price) FROM fullSalesView

WHERE NameType='против гриппа'

GROUP BY Address, MONTH(DateCheck)

ORDER BY 3 DESC



Это тоже срез куба – в измерении «Товар» зафиксировано значение для типа товара. По измерению «Аптека» оставлен исходный уровень детализации, а по измерению «Чек» данные агрегированы в масштабе месяцев.

- А сколько реализовано товара с названием «Товар 117» в «Аптеке 10» за август текущего года?

В этом запросе зафиксированы значения по измереням «Товар» и «Аптека». Для измерения «Чек» данные агрегированы по месяцам и зафиксировано значение месяца и года.

Для таких запросов самым удобным подходом будет создание хранимой процедуры, и чем больше у неё будет параметров, тем лучше:
CREATE PROC detailSales

@address VARCHAR(50),

@nameArticle VARCHAR(50),

@month INT,

@year INT

as

SELECT SUM(Quantity*Price) FROM fullSalesView



WHERE Address=@Address AND NameArticle=@NameArticle AND

YEAR(DateCheck)=@year AND MONTH(DateCheck)=@month


EXEC detailSales 'Адрес 10', 'Товар 117', 8, 2012

Можно сформулировать огромное количество таких запросов. Заранее очень сложно предугадать, какие именно данные и в каком разрезе понадобятся пользователям. Было бы гораздо удобнее предоставить самим пользователям возможность в визуальном режиме, без написания сложных SQL-команд выбирать данные по нужным критериям. Именно для этого и предназначены специализированные приложения для работы с хранилищами данных. В таких приложениях, кстати, очень легко выполнить следующий запрос (а написать его на обычном SQL довольно сложно):

- А можно получить такую таблицу, чтобы столбцами были, например, месяцы, а в строках находились типы товаров и итоги продаж по месяцам?

Такие таблицы называются перекрёстными (или кросс-таблицами). Получить такую таблицу стандартными средствами языка SQL можно только для заранее заданных количества и названий столбцов. Для этого используется SELECT с ключевым словом PIVOT (развернуть). Попробуйте разработать такой запрос самостоятельно.

Задание 3. Напишите запросы, реализующие выборку из нескольких таблиц – с записью полученных данных в новую таблицу и с созданием представления (3 балла). Напишите не менее 5 разнообразных запросов для получения срезов куба, с применением группировок и агрегирующих функций (5 баллов). Напишите хранимую процедуру для получения отдельной ячейки куба (3 балла). Создайте кросс-таблицу (4 балла). (Итого 15 баллов).

Этап 4. ETL – extract, transform, load (извлечь, преобразовать, загрузить).

Очистка и преобразование данных представляют собой очень важные процедуры перед загрузкой информации в хранилище данных. Здесь возникает вопрос: с какими данными производить эти операции – с данными из исходных таблиц или же с промежуточными результатами? В нашей задаче будем считать, что данные из исходных таблиц нам модифицировать нельзя, и займемся поиском некорректных и неполных данных и их очисткой в таблице, которую создали на предыдущем этапе. Например, с точки зрения полноты данных имеет смысл проверить важные поля на пустоту:

SELECT * FROM fullSalesTable WHERE nameArticle IS NULL

SELECT * FROM fullSalesTable WHERE nameType IS NULL

SELECT * FROM fullSalesTable WHERE nameFirm IS NULL


И т.п. Если такие поля найдены, то следует либо их заполнить реальными данными, либо просто избавиться от таких строк, поскольку они имеют мало смысла для дальнейшей обработки. В приведенных выше примерах отсутствие названия лекарства (nameArticle) означает явную ошибку ввода, поэтому такие строки можно удалить (напишите соответствующую команду!). Если название лекарства есть, но отсутствует тип лекарства (nameType) или название фирмы (nameFirm), их можно попробовать найти в соответствующих таблицах и откорректировать пустую ячейку (напишите для этой операции запрос или хранимую процедуру!). (На самом деле, в нашем примере эти 3 поля заведомо не могут быть пустыми – подумайте, почему?)

Далее, например, мы хотим в дальнейшем использовать только данные за 2010 - 2012 годы. Всё остальное из таблицы следует удалить.

SELECT * FROM fullSalesTable WHERE YEAR(dateCheck) NOT IN (2010,2011,2012)

DELETE FROM fullSalesTable WHERE YEAR(dateCheck) NOT IN (2010,2011,2012)

Также полезной в нашем случае будет следующая проверка: посчитаем, сколько было продаж в таблице Sale и сколько строк попало в таблицу fullSalesTable.

SELECT COUNT(*) FROM fullSalesTable

SELECT COUNT(*) FROM Sale

Если не все строки из таблицы Sales попали в таблицу fullSalesTable, причина может быть в следующем. Таблица fullSalesTable собиралась из 6 таблиц и, возможно, где-то было пропущено значение, которое участвовало в условии связи (мы использовали INNER JOIN –внутреннее соединение). Пусть, например, у нас есть товар, который не привязан к типу лекарства:

SELECT * FROM Article WHERE numType IS NULL

и этот товар участвовал в продажах:

SELECT * FROM Sale WHERE numArticle IN

(SELECT numArticle FROM Article WHERE numType IS NULL)



Для такого товара следует выяснить, к какому типу лекарств он относится, заполнить поле numType, а затем добавить информацию о продажах этого товара в таблицу fullSalesTable. Здесь можно воспользоваться такой уловкой: после исправления типа лекарства информация о продажах этого лекарства сразу же попадет в представление fullSalesView, из которого мы эти продажи и скопируем:

INSERT INTO fullSalesTable

SELECT * FROM fullSalesView WHERE nameArticle NOT IN

(SELECT nameArticle FROM fullSalesTable)

Проверки корректности данных можно также провести и для таблицы льготников, которую мы загрузили из внешнего файла. Например, проверим корректность названий лекарств (т. е., соответствие названий нашему справочнику):

SELECT * FROM SocialReceipt WHERE nameArticle NOT IN

(SELECT nameArticle FROM Article)



Получили строку с названием, которое отсутствует в нашем справочнике. Что делать с такими данными? Либо выяснить, какое название имелось в виду, либо просто удалить эту строку.

Преобразование данных не ограничивается только исправлением ошибок. Иногда приходится, например, объединять в рамках одной таблицы данные из нескольких источников. Например, сделаем таблицу, содержащую всю информацию о реализации лекарств – и о продажах, и о льготной реализации.

Создадим общую таблицу со структурой, как у fullSalesTable, но с простым первичным ключом:

CREATE TABLE fullRealization

(

NameArticle VARCHAR(50),



Price Numeric(6,2),

NameType VARCHAR(50),

NameFirm VARCHAR(50),

Address VARCHAR(50),

DateCheck DATETIME,

NumCheck INT,

Quantity INT,

ID INT PRIMARY KEY IDENTITY )

Добавим в нее продажи:

INSERT INTO fullRealization SELECT * FROM fullSalesTable

А теперь нужно добавить информацию о льготной реализации из таблицы SocialReceipt. Обратите внимание, как заполняются недостающие поля.

INSERT INTO fullRealization

SELECT sr.NameArticle, 0 AS Price, t.NameType,

f.NameFirm, '' AS Address, sr.DateCust, 0 AS NumCheck,

sr.quantityCust

FROM SocialReceipt sr JOIN Article a ON sr.NameArticle=g.NameArticle

JOIN Firm f ON f.numFirm=a.numFirm

JOIN Type t ON t.numType=a.numType



Задание 4. Произведите очистку данных: напишите запросы, которые находят пустые значения, неверные или неполные данные и, при необходимости, корректируют их (5 баллов). Напишите запросы, которые преобразуют данные (4 балла). Не ограничивайтесь примерами, приведенными в данном параграфе, придумывайте свои собственные преобразования! (Итого 9 баллов)

Этап 5. ETL – extract, transform, load (извлечь, преобразовать, загрузить).

Учебная версия программы DEDUCTOR, к сожалению, не позволяет напрямую подключаться к SQL Server (у промышленной версии такого ограничения нет). Поэтому придется обмениваться данными через текстовый файл.

У вас есть следующие варианты выполнения данного задания. Самый простой способ состоит в том, что вы выгружаете одну многомерную таблицу со всей информацией, созданную на 3 этапе. Тогда в программе DEDUCTOR вы не будете создавать настоящее хранилище данных (и не получите за это баллы в количестве 10 шт.), а в качестве хранилища будет выступать этот текстовый файл. Все возможности работы с OLAP-кубами данных, диаграммами, анализ данных для такого источника данных будут доступны.

Более сложный вариант, предполагающий создание настоящего хранилища данных в DEDUCTOR (в формате СУБД FireBird) требует создания отдельных текстовых файлов для таблицы фактов (Продажи) и для всех измерений (Типы, Товары, Аптеки и пр.) Рассмотрим обе эти возможности.

Примеры реализации:

1) Выгрузим подготовленную таблицу с детальной информацией о продажах и льготной реализации в текстовый файл. Для этого снова обратимся к программе массовой загрузки bcp (bulk copy procedure).

Вспомним, что эта команда запускается из командной строки Windows (Пуск – Выполнить – cmd –OK ). В нашем случае формат команды следующий:

bcp drugstores.dbo.fullRealization out fullRealization.txt -T -w -S HOME\SQLEXPRESS -C 1251 -t; -r\n

Рассмотрим параметры этой команды, которые не встречались нам раньше.

out – направление потока данных: из SQL server наружу;

-w – выполняет операцию массового копирования, используя символы Юникода. При использовании этого параметра не запрашивается тип данных каждого поля, для хранения данных используется тип nchar, отсутствуют префиксы, в качестве разделителя полей используется символ табуляции \t, а в качестве признака конца строки — символ новой строки \n.

-r\n – задается разделитель конца строки – символ ‘\n’.

Получим файл с таким содержимым:



Для того чтобы формат нашего файла соответствовал программе DEDUCTOR, откроем полученный файл в «Блокноте», добавим в качестве первой строки заголовки столбцов:



Товар; Цена; Тип; Фирма; Аптека; Дата; Чек; Количество

а затем сохраним его в формате ANSI:





Примечание: в выгруженном файле имеются даты, которые в своем составе содержат миллисекунды в виде .000. Эти миллисекунды в дальнейшем вызовут большие проблемы при загрузке в Deductor Studio, поэтому от них следует избавиться. Самый простой способ – открыть файл в текстовом редакторе и произвести автоматическую замену, например, заменить строку «.000;» на строку «;». Программа «Блокнот» для этой операции может быть слишком медленной, лучше использовать, например, MS Word:

2) Теперь рассмотрим выгрузку данных в несколько текстовых файлов – отдельно для таблицы фактов и отдельно для всех измерений. (Выгружаем только продажи, льготную реализацию для упрощения работы брать не будем.)


Типы лекарств:

bcp drugstores.dbo.Type out types.txt -T -w -S HOME\SQLEXPRESS -C 1251 -t; -r\n


Фирмы-производители:

bcp drugstores.dbo.Firm out firms.txt -T -w -S HOME\SQLEXPRESS -C 1251 -t; -r\n


Чеки:

bcp drugstores.dbo.Bill out bills.txt -T -w -S HOME\SQLEXPRESS -C 1251 -t; -r\n


Продажи:

bcp drugstores.dbo.Sale out sales.txt -T -w -S HOME\SQLEXPRESS -C 1251 -t; -r\n


Из таблицы «Аптеки» возьмем только номер и адрес, для этого придется написать SELECT и указать, что тип операции – не “out”, а “queryout”:
bcp "SELECT NumDrug, Address FROM drugstores.dbo.drugstore" queryout drugstores.txt -T -w -S HOME\SQLEXPRESS -C 1251 -t; -r\n
Из таблицы «Товары» тоже возьмем только некоторые столбцы, для этого придется написать SELECT и указать, что тип операции – не “out”, а “queryout”:

bcp "SELECT NumArticle, NameArticle, NumType, NumFirm FROM drugstores.dbo.article" queryout articles.txt -T -w -S HOME\SQLEXPRESS -C 1251 -t; -r\n

Задание 5. Выгрузите подготовленные данные в один или несколько текстовых файлов. Задайте в этих файлах заголовки столбцов. Не забудьте сохранить файлы в формате ANSI. В тех файлах, где используется тип дата+время, избавьтесь от миллисекунд. (Итого 5 баллов).

  1   2


База данных защищена авторским правом ©infoeto.ru 2022
обратиться к администрации
Как написать курсовую работу | Как написать хороший реферат
    Главная страница