Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АрхитектураБиологияГеографияДругоеИностранные языки
ИнформатикаИсторияКультураЛитератураМатематика
МедицинаМеханикаОбразованиеОхрана трудаПедагогика
ПолитикаПравоПрограммированиеПсихологияРелигия
СоциологияСпортСтроительствоФизикаФилософия
ФинансыХимияЭкологияЭкономикаЭлектроника

Перекрестные соединения

Подзапросы, ориентированные на задачи | Gt; SUM(avail_balance) tot_deposits _> FROM account | Подзапросы в условиях фильтрации | Подзапросы как генераторы выражений | Gt; SUM(a.avail_balance) tot_deposits _> FROM account a | Краткий обзор подзапросов | Упражнения | Внешние соединения | Сравнение левосторонних и правосторонних внешних соединений | Трехсторонние внешние соединения |


Читайте также:
  1. ANSI_синтаксис соединения
  2. А) определение группы соединения обмоток;
  3. Бор и его соединения. Нахождение в породах, в вулканических и поствулканических процессах. Источники бора в осадочных породах.
  4. В основе процесов получения уретановых эластомеров лежит реакция поликонденсации диизоцианатов с соединениями, имеющими по крайней мере две гидроксильные группы.
  5. Внешние соединения
  6. Внутренние соединения
  7. Геохимия As. Гидротермальный процесс и соединения As.

 

В главе 5 была представлена концепция декартова произведения, ко_ торое, в сущности, является результатом соединения нескольких таб_ лиц без указания каких_либо условий соединения. Декартово произве_ дение довольно часто используется в результате случайности (т. е. ко_ гда разработчики просто забывают добавить в блок from условие соеди_ нения), но на самом деле не так уж широко распространено. Однако если действительно требуется получить декартово произведение двух таблиц, должно быть задано перекрестное соединение:

 

mysql> SELECT pt.name, p.product_cd, p.name

_> FROM product p CROSS JOIN product_type pt;

 

+_______________________________+____________+_________________________+ | name | product_cd | name | +_______________________________+____________+_________________________+

 

| Customer Accounts | AUT | auto loan |
| Customer Accounts | BUS | business line of credit |
| Customer Accounts | CD | certificate of deposit |

 

      Глава 10. И снова соединения
       
| Customer Accounts | CHK | checking account |
| Customer Accounts | MM | money market account |
| Customer Accounts | MRT | home mortgage |
| Customer Accounts | SAV | savings account |
| Customer Accounts | SBL | small business loan |
| Insurance Offerings | AUT | auto loan |
| Insurance Offerings | BUS | business line of credit |
| Insurance Offerings | CD | certificate of deposit |
| Insurance Offerings | CHK | checking account |
| Insurance Offerings | MM | money market account |
| Insurance Offerings | MRT | home mortgage |
| Insurance Offerings | SAV | savings account |
| Insurance Offerings | SBL | small business loan |
| Individual and Business Loans | AUT | auto loan |
| Individual and Business Loans | BUS | business line of credit |
| Individual and Business Loans | CD | certificate of deposit |
| Individual and Business Loans | CHK | checking account |
| Individual and Business Loans | MM | money market account |
| Individual and Business Loans | MRT | home mortgage |
| Individual and Business Loans | SAV | savings account |
| Individual and Business Loans | SBL | small business loan |

 

+_______________________________+____________+_________________________+ 24 rows in set (0.00 sec)

 

Этот запрос формирует декартово произведение таблиц product и prod_ uct_type. В результате получаем 24 строки (8 строк product умножают_ ся на 3 строки product_type). Но теперь, когда известно, что такое пере_ крестное соединение и как оно задается, надо определиться с тем, за_ чем оно используется. Большинство книг по SQL описывают, что такое перекрестное соединение, и затем говорят, что используется оно ред_ ко. Но мне бы хотелось поделиться с читателем ситуациями, в кото_ рых я нахожу перекрестное соединение довольно полезным.

 

В главе 9 обсуждалось, как использовать подзапросы для создания таб_ лиц. Используемый пример показывал, как построить таблицу, вклю_ чающую три строки, которая могла быть соединена с другими таблица_ ми. Вот таблица из того примера:

 

mysql> SELECT 'Small Fry' name, 0 low_limit, 4999.99 high_limit
_> UNION ALL          
_> SELECT 'Average Joes' name, 5000 low_limit, 9999.99 high_limit
_> UNION ALL          
_> SELECT 'Heavy Hitters' name, 10000 low_limit, 9999999.99 high_limit;
+_______________+___________+____________+
| name   | low_limit | high_limit |
+_______________+___________+____________+
| Small Fry |   | 4999.99 |
| Average Joes |   | 9999.99 |
| Heavy Hitters |   | 9999999.99 |

 

+_______________+___________+____________+ 3 rows in set (0.00 sec)


 

Перекрестные соединения  
   

 

Хотя эта таблица является именно тем, что требовалось для разделения клиентов на три группы на основании их совокупного остатка на счете, эта стратегия слияния однострочных таблиц с помощью оператора union all не очень подходит, если требуется соорудить большую таблицу.

 

Например, требуется создать запрос, формирующий строку для каж_ дого дня 2004 года, но в БД нет таблицы, содержащей строки для всех дней. Используя стратегию из примера главы 9, можно было бы сде_ лать что_то вроде этого:

 

SELECT '2004_01_01' dt UNION ALL

 

SELECT '2004_01_02' dt UNION ALL

 

SELECT '2004_01_03' dt UNION ALL

 

...

 

...

 

...

 

SELECT '2004_12_29' dt UNION ALL

 

SELECT '2004_12_30' dt UNION ALL

SELECT '2004_12_31' dt

 

Создавать запрос, соединяющий результаты 366 запросов, немного уто_ мительно, поэтому, наверное, нужна другая стратегия. Что если сгене_ рировать таблицу с 366 строками (2004 год был високосным) и одним столбцом, содержащим число от 0 до 366, и затем добавлять это число дней к 1 января 2004? Вот одна из возможных методик формирования подобной таблицы:

 

mysql> SELECT ones.num + tens.num + hundreds.num
_> FROM      
_> (SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num) ones
_> CROSS JOIN  
_> (SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL

 

        Глава 10. И снова соединения
       
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num) tens
_> CROSS JOIN  
_> (SELECT 0 num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num) hundreds;

 

+____________________________________+ | ones.num + tens.num + hundreds.num | +____________________________________+

 

|   |
|   |
|   |
|   |
|   |
|   |
|   |
|   |
|   |
|   |
|   |
|   |
|   |
...    
...    
...    
|   |
|   |
|   |
|   |
|   |
|   |
|   |
|   |
|   |

 

+____________________________________+ 400 rows in set (0.00 sec)

 

Если найти декартово произведение трех наборов – {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 10, 20, 30, 40, 50, 60, 70, 80, 90} и {0, 100, 200, 300} – и сло_ жить значения во всех трех столбцах, получится результат, состоя_ щий из 400 строк, содержащих все числа от 0 до 399. Хотя это больше 366 строк, необходимых для формирования набора дней 2004 года, из_ бавиться от лишних строк достаточно просто. Вскоре я покажу, как это сделать.

 

Следующий шаг – преобразовать числа в набор дат. Для этого восполь_ зуемся функцией date_add() и добавим каждое число в результирую_ щий набор к 1 января 2004 года. Затем введем условие фильтрации, чтобы отбросить все даты 2005 года.


 

Перекрестные соединения      
 
mysql> SELECT DATE_ADD('2004_01_01',
_> INTERVAL (ones.num + tens.num + hundreds.num) DAY) dt
_> FROM      
_> (SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num) ones  
_> CROSS JOIN  
_> (SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num UNION ALL
_> SELECT   num) tens  
_> CROSS JOIN  
_> (SELECT   num UNION ALL
_> SELECT 100 num UNION ALL
_> SELECT 200 num UNION ALL
_> SELECT 300 num) hundreds
_> WHERE DATE_ADD('2004_01_01',
_> INTERVAL (ones.num + tens.num + hundreds.num) DAY) < '2005_01_01';
+____________+      
| dt |      
+____________+      
| 2004_01_01 |      

 

| 2004_01_02 | | 2004_01_03 | | 2004_01_04 | | 2004_01_05 | | 2004_01_06 | | 2004_01_07 | | 2004_01_08 | | 2004_01_09 | | 2004_01_10 |

 

...

 

...

 

...

 

| 2004_02_20 | | 2004_02_21 | | 2004_02_22 | | 2004_02_23 |


 

210 Глава 10. И снова соединения

 

| 2004_02_24 | | 2004_02_25 | | 2004_02_26 | | 2004_02_27 | | 2004_02_28 | | 2004_02_29 | | 2004_03_01 |

 

...

 

...

 

...

 

| 2004_12_20 | | 2004_12_21 | | 2004_12_22 | | 2004_12_23 | | 2004_12_24 | | 2004_12_25 | | 2004_12_26 | | 2004_12_27 | | 2004_12_28 | | 2004_12_29 | | 2004_12_30 | | 2004_12_31 | +____________+

 

366 rows in set (0.01 sec)

 

В этом подходе замечательно то, что результирующий набор автомати_ чески включает 29 февраля без всяких дополнительных вмеша_ тельств, поскольку сервер БД вычисляет его, когда добавляет 59 дней к 1 января 2004 года.

 

Теперь, когда у нас есть механизм получения всех дней 2004 года, что мы должны с ними сделать? Ну, может потребоваться сгенерировать запрос, по которому будут выводиться все дни 2004 года с номерами счетов, открытых в каждый из дней, с числом осуществленных опера_ ций и т. д. Вот пример, дающий ответ на первый вопрос:

 

mysql> SELECT days.dt, COUNT(a.account_id)
_> FROM account a RIGHT OUTER JOIN
_> (SELECT DATE_ADD('2004_01_01',
_> INTERVAL (ones.num + tens.num + hundreds.num) DAY) dt
_> FROM    
_> (SELECT 0 num UNION ALL
_> SELECT 1 num UNION ALL
_> SELECT 2 num UNION ALL
_> SELECT 3 num UNION ALL
_> SELECT 4 num UNION ALL
_> SELECT 5 num UNION ALL
_> SELECT 6 num UNION ALL
_> SELECT 7 num UNION ALL
_> SELECT 8 num UNION ALL
_> SELECT 9 num) ones  
_> CROSS JOIN  

 

Перекрестные соединения      
         
_> (SELECT 0 num UNION ALL    
_> SELECT 10 num UNION ALL  
_> SELECT 20 num UNION ALL  
_> SELECT 30 num UNION ALL  
_> SELECT 40 num UNION ALL  
_> SELECT 50 num UNION ALL  
_> SELECT 60 num UNION ALL  
_> SELECT 70 num UNION ALL  
_> SELECT 80 num UNION ALL  
_> SELECT 90 num) tens    
_> CROSS JOIN    
_> (SELECT 0 num UNION ALL    
_> SELECT 100 num UNION ALL  
_> SELECT 200 num UNION ALL  
_> SELECT 300 num) hundreds  
_> WHERE DATE_ADD('2004_01_01',
_> INTERVAL (ones.num + tens.num + hundreds.num) DAY) <
_>   '2005_01_01') days    
_> ON days.dt = a.open_date    
_> GROUP BY days.dt;    
+____________+_____________________+
| dt   | COUNT(a.account_id) |
+____________+_____________________+
| 2004_01_01 |     |
| 2004_01_02 |     |
| 2004_01_03 |     |
| 2004_01_04 |     |
| 2004_01_05 |     |
| 2004_01_06 |     |
| 2004_01_07 |     |
| 2004_01_08 |     |
| 2004_01_09 |     |
| 2004_01_10 |     |
| 2004_01_11 |     |
| 2004_01_12 |     |
| 2004_01_13 |     |
| 2004_01_14 |     |
| 2004_01_15 |     |
...          
...          
...          
| 2004_12_15 |     |
| 2004_12_16 |     |
| 2004_12_17 |     |
| 2004_12_18 |     |
| 2004_12_19 |     |
| 2004_12_20 |     |
| 2004_12_21 |     |
| 2004_12_22 |     |
| 2004_12_23 |     |
| 2004_12_24 |     |

 

      Глава 10. И снова соединения
     
| 2004_12_25 |   |
| 2004_12_26 |   |
| 2004_12_27 |   |
| 2004_12_28 |   |
| 2004_12_29 |   |
| 2004_12_30 |   |
| 2004_12_31 |   |

 

+____________+_____________________+ 366 rows in set (0.03 sec)

 

Это один из самых интересных запросов, встречавшихся до сих пор в данной книге. Его ценность в том, что он включает перекрестные со_ единения, внешние соединения, функцию работы с датами, группи_ ровку, операции с множествами (union all) и агрегатную функцию (count()). Это не самое элегантное решение заданной проблемы, но оно послужит примером того, как с небольшой долей творчества и твер_ дым знанием языка программирования даже такой редко используе_ мый механизм, как перекрестные соединения, можно сделать могуще_ ственным инструментом в наборе инструментов SQL.

 


Дата добавления: 2015-08-17; просмотров: 70 | Нарушение авторских прав


<== предыдущая страница | следующая страница ==>
Рекурсивные внешние соединения| Естественные соединения

mybiblioteka.su - 2015-2024 год. (0.019 сек.)