JOIN MySQL Объединение таблиц, варианты
Выборку будем делать из двух таблиц
id name id name
-- ---- -- ----
1 Яблоко 1 Тыква
2 Ананас 2 Яблоко
3 Банан 3 Дыня
4 Груша 4 Банан
INNER JOIN
SELECT * FROM tableA INNER JOIN tableB ON tableA.name = tableB.nameid name id name
-- ---- -- ----
1 Яблоко 2 Яблоко
3 Банан 4 Банан
Выбираются только те записи, которые совпадают в обоих таблицах.
—————————————————————
LEFT OUTER JOIN
SELECT * FROM tableA LEFT OUTER JOIN tableB ON tableA.name = tableB.nameid name id name
-- ---- -- ----
1 Яблоко 2 Яблоко
2 Ананас null null
3 Банан 4 Банан
4 Груша null null
Все записи из таблицы А и совпавшие записи из таблицы B. Если совпадение отсутствует, то правая сторона будет содержать значение null, т.к. управляющая таблица левая, об этом говорит ключевое слово LEFT.
—————————————————————
LEFT OUTER JOIN WHERE B id IS NULL
SELECT * FROM tableA LEFT OUTER JOIN tableB ON tableA.name = tableB.name
WHERE tableB.id IS nullid name id name
-- ---- -- ----
2 Ананас null null
4 Груша null null
Уникальные в А. Записи из таблицы А, которые не совпадают с записями из таблицы В.
Если немного изменить запрос, то получим уникальные записи из таблицы B.
SELECT * FROM tableA RIGHT OUTER JOIN tableB ON tableA.name = tableB.name
WHERE tableA.id IS nullid name id name
-- ---- -- ----
null null 1 Тыква
null null 3 Дыня
—————————————————————
FULL OUTER JOIN
SELECT * FROM tableA FULL OUTER JOIN tableB ON tableA. name = tableB.nameid name id name
-- ---- -- ----
1 Яблоко 2 Яблоко
2 Ананас null null
3 Банан 4 Банан
4 Груша null null
null null 1 Тыква
null null 3 Дыня
Выбираем все записи в обоих таблицах с совпадением записей с обоих сторон, где это возможно. Если совпадения нет, то пропускающая сторона будет содержать значение null.
—————————————————————
FULL OUTER JOIN WHERE A or B id IS NULL
SELECT * FROM tableA FULL OUTER JOIN tableB ON tableA.name = tableB.name
WHERE tableA.id IS null OR tableB.id IS nullid name id name
-- ---- -- ----
2 Ананас null null
4 Груша null null
null null 1 Тыква
null null 3 Дыня
Уникальные в обоих.
Статья основана на материалах: http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html
Разбираемся с mySQL JOIN, визуальное представление. « Блог вебмастера Романа Чернышова
На протяжении немалого времени, в начале своей карьеры веб-разработчика, я работал с базой данный как умел, а умел я не многое. Составлял простые примитивные запросы, а порою даже вставлял запросы в циклы. На тот момент мне к сожалению не попалась в руки правильная книжка по mySQL и учить приходилось методом проб и ошибок. Множество статей в интернете как-то не сразу донесли до меня замечательный mySQL запрос — JOIN.
В этой публикации я расскажу о всех возможных вариантах работы с JOIN и более того, представлю принцип работы каждой команды — визуально.
- INNER JOIN
- LEFT JOIN
- RIGHT JOIN
- OUTER JOIN
- LEFT JOIN EXCLUDING INNER JOIN
- RIGHT JOIN EXCLUDING INNER JOIN
- OUTER JOIN EXCLUDING INNER JOIN
Отдельно стоит отметить пункты 5,6 и 7. На самом деле эти запросы не соединяют две таблицы, а наоборот исключают из одной таблицы столбцы присутствующие в другой. На деле это может оказать очень полезным.
Inner JOIN
Один из самых распространенных запросов, встречается предельно часто. Этот запрос вернет все записи из левой таблицы (таб. А) и записи из (таб. В), но при этом возвращены будут только совпадающие столбцы.
Пример запроса:
SELECT <select_list> FROM Table_A A INNER JOIN Table_B B ON A.Key = B.Key |
Left JOIN
Данный запрос вернет все столбцы из левой таблицы (таб. А), а также все столбцы из правой таблицы (таб. В) но только которые совпадают со столбцами из левой таблицы.
Пример запроса:
SELECT <select_list> FROM Table_A A LEFT JOIN Table_B B ON A.Key = B.Key |
Right JOIN
Аналогичен предыдущему запросу, но уже вернет все столбцы из правой таблицы (таб. В), а также все столбцы из левой таблицы (таб. А) которые совпадают со столбцами из правой таблицы.
Пример запроса:
SELECT <select_list> FROM Table_A A RIGHT JOIN Table_B B ON A.Key = B.Key |
Outer JOIN
Часто данный запрос записывают как FULL OUTER JOIN или FULL JOIN, все вариации выполняют одно действие, а именно возвращают все столбцы из обоих таблиц, при этом совпадающие столбцы будут перекрыты столбцами из левой таблицы.
Пример запроса:
SELECT <select_list> FROM Table_A A FULL OUTER JOIN Table_B B ON A.Key = B.Key |
Left Excluding JOIN
Этот запрос вернет все столбцы из левой таблицы (таб. А), которые не совпадают со столбцами из правой таблицы (таб. В).
Пример запроса:
SELECT <select_list> FROM Table_A A LEFT JOIN Table_B B ON A.Key = B.Key WHERE B.Key IS NULL |
Right Excluding JOIN
Пример запроса:
SELECT <select_list> FROM Table_A A RIGHT JOIN Table_B B ON A.Key = B.Key WHERE A.Key IS NULL |
Outer Excluding JOIN
Этот запрос вернет все записи из левой и правой таблицы, но при этом исключит совпадающие столбцы.
Пример запроса:
SELECT <select_list> FROM Table_A A FULL OUTER JOIN Table_B B ON A.Key = B.Key WHERE A.Key IS NULL OR B.Key IS NULL |
Надеюсь этот пост пригодится многим начинающий веб-разработчикам, ведь запомнить сразу все отличия запросов друг от друга очень сложно, ввиду чего многие пользуются одним, двумя типами запросов и забывают про силу и мощь mySQL.
В качестве шпаргалки приведу изображение со всеми типами JOIN запросов и кратким примером кода.
mySQL join, mysql
MySQL ВНУТРЕННЕЕ СОЕДИНЕНИЕ
INNER JOIN
используется для возврата данных из нескольких таблиц. В частности, INNER JOIN
предназначен для случаев, когда вы заинтересованы только в возврате записей, в которых есть хотя бы одна строка в обеих таблицах, соответствующих условию соединения.
Рассмотрим следующие таблицы:
Если мы хотим выбрать данные из двух выделенных полей ( страна
и город
), мы можем выполнить следующий запрос (который включает внутреннее соединение):
ВЫБЕРИТЕ город, страну ИЗ города INNER JOIN страна ON city.country_id = страна.country_id;
И результат будет выглядеть так:
В приведенном выше примере мы используем внутреннее соединение для отображения списка городов рядом со страной, которой он принадлежит. Информация о городе находится в таблице, отличной от информации о стране. Поэтому мы соединяем две таблицы, используя поле
— так как это общее поле в обеих таблицах (это поле внешнего ключа).
Вот схема этих двух таблиц (с выделенной связью внешнего ключа):
Квалификация полей
Вы заметите, что в приведенном выше примере мы уточнили имена некоторых полей с соответствующими именами таблиц. В частности, последняя строка гласит: город .country_id = страна .country_id;
.
Мы делаем это, потому что имена полей совпадают ( country_id
). Если бы мы не уточнили его именами таблиц (т.е. идентификатор_страны = идентификатор_страны;
city
или в таблице country
.Если мы не уточним столбцы, MySQL выдаст ошибку неоднозначного столбца. Это будет примерно так:
Использование псевдонимов
При уточнении имен столбцов вы можете использовать псевдонимы таблиц, чтобы сократить запрос и сэкономить время ввода.
Например, приведенный выше пример можно было бы переписать следующим образом:
ВЫБЕРИТЕ город, страну ИЗ города а INNER JOIN страна b ON a.country_id = b.country_id;
Внутренние соединения с
GROUP BY
и агрегатными функциямиВ следующем примере мы меняем его местами и предоставляем список стран в одном столбце с количеством городов, которые содержит каждая страна, в другом столбце.
Для этого мы используем агрегатную функцию COUNT()
для подсчета количества городов для каждой страны, затем GROUP BY Предложение
для группировки результатов по странам.
ВЫБЕРИТЕ страну, COUNT(город) ИЗ страны а ВНУТРЕННЕЕ СОЕДИНЕНИЕ город b ON a.country_id = b.country_id СГРУППИРОВАТЬ ПО странам;
Результат:
Разница между типами соединения проста.
-
ВНУТРЕННЕЕ СОЕДИНЕНИЕ
- Возвращает только строки, в которых есть совпадающая строка в
-
ЛЕВОЕ СОЕДИНЕНИЕ
- Все строки из слева 9Таблица 0081 будет возвращена, даже если в правильной таблице нет соответствующей строки.
-
ПРАВОЕ СОЕДИНЕНИЕ
- Будут возвращены все строки из правой таблицы, даже если в левой таблице нет соответствующей строки.
В примерах на этой странице используется образец базы данных Sakila.
Пошаговое руководство по SQL Inner Join
Каждую минуту организации генерируют и анализируют непревзойденные объемы данных. В этой статье мы покажем, как мы можем использовать
Соединения SQL
Прежде чем мы начнем с SQL Inner Join, я хотел бы вызвать здесь SQL Join. Присоединение — это широко используемое предложение в SQL Server, в основном предназначенное для объединения и извлечения данных из двух или более таблиц. В реальной реляционной базе данных данные структурированы в большом количестве таблиц, и поэтому существует постоянная потребность в объединении этих нескольких таблиц на основе логических связей между ними. В SQL Server существует четыре основных типа соединений: внутреннее, внешнее (левое, правое, полное), самостоятельное и перекрестное соединение. Чтобы получить краткий обзор всех этих объединений, я бы порекомендовал пройти по этой ссылке, обзору типов соединений SQL и учебному пособию.
Эта статья посвящена внутреннему соединению в SQL Server, так что давайте перейдем к нему.
Определение внутреннего соединения SQL
Предложение Inner Join в SQL Server создает новую таблицу (не физическую) путем объединения строк, имеющих совпадающие значения в двух или более таблицах. Это объединение основано на логической связи (или общем поле) между таблицами и используется для извлечения данных, которые появляются в обеих таблицах.
Предположим, у нас есть две таблицы, таблица A и таблица B, которые мы хотели бы соединить с помощью SQL Inner Join. Результатом этого соединения будет новый результирующий набор, возвращающий совпадающие строки в обеих этих таблицах. Часть пересечения, выделенная черным цветом ниже, показывает данные, полученные с помощью Inner Join в SQL Server.
Синтаксис внутреннего соединения SQL Server
Ниже приведен основной синтаксис Inner Join.
SELECT Column_list
FROM TABLE1
INNER JOIN TABLE2
ON Table1. ColName = Table2.ColName
Синтаксис внутреннего соединения в основном сравнивает строки таблицы Table1 с таблицей Table2, чтобы проверить, совпадает ли что-либо на основе условия, указанного в предложении ON. Когда условие соединения выполнено, оно возвращает совпадающие строки в обеих таблицах с выбранными столбцами в предложении SELECT.
Предложение SQL Inner Join такое же, как и предложение Join, и работает так же, если мы не указываем тип (INNER) при использовании предложения Join. Короче говоря, внутреннее соединение — это ключевое слово по умолчанию для соединения, и оба они могут использоваться взаимозаменяемо.
Примечание. Мы будем использовать ключевое слово «внутреннее» соединение в этой статье для большей ясности. Вы можете опустить его при написании своих запросов и также можете использовать только «Присоединиться».
Внутреннее соединение SQL в действии
Давайте попробуем понять концепцию внутреннего соединения на примере интересной выборки данных, касающейся пиццерии и ее распределения продуктов питания. Сначала я собираюсь создать две таблицы: таблицу «PizzaCompany», которая управляет различными филиалами пиццерий в нескольких городах, и таблицу «Foods», в которой хранятся данные о распределении продуктов питания по этим компаниям. Вы можете выполнить приведенный ниже код, чтобы создать и заполнить данные в этих двух таблицах. Все эти данные являются гипотетическими и вы можете создать их в любой из ваших существующих баз данных.
1 2 3 4 5 6 7 8 7 0 107 002 11 12 13 14 15 16 | CREATE TABLE [dbo].[PizzaCompany] ( [CompanyId] [int] IDENTITY(1,1) PRIMARY KEY CLUSTERED, [CompanyName] [CompanyName](50) , 7 90 varchar](30) ) SET IDENTITY_INSERT [dbo].[PizzaCompany] ON; ВСТАВИТЬ В [dbo].[PizzaCompany] ([CompanyId], [CompanyName], [CompanyCity]) VALUES(1,’Dominos’,’Los Angeles’) ; ВСТАВИТЬ В [dbo]. [PizzaCompany] ([CompanyId], [CompanyName], [CompanyCity]) VALUES(2,’Pizza Hut’,’Сан-Франциско’) ; ВСТАВИТЬ В [dbo].[PizzaCompany] ([CompanyId], [CompanyName], [CompanyCity]) VALUES(3,’Папа Джонс’,’Сан-Диего’) ; ВСТАВИТЬ В [dbo].[PizzaCompany] ([CompanyId], [CompanyName], [CompanyCity]) VALUES(4,’Ah Pizz’,’Fremont’) ; ВСТАВИТЬ В [dbo].[PizzaCompany] ([CompanyId], [CompanyName], [CompanyCity]) VALUES(5,’Nino Pizza’,’Las Vegas’) ; ВСТАВИТЬ В [dbo].[PizzaCompany] ([CompanyId], [CompanyName], [CompanyCity]) VALUES(6,’Пиццерия’,’Бостон’) ; ВСТАВИТЬ В [dbo].[PizzaCompany] ([CompanyId], [CompanyName], [CompanyCity]) VALUES(7,’chuck e cheese’,’Chicago’) ;
ВЫБЕРИТЕ * ОТ PizzaCompany: |
Вот как выглядят данные в таблице PizzaCompany:
Давайте сейчас создадим и заполним таблицу Foods. CompanyID в этой таблице — это внешний ключ, который ссылается на первичный ключ таблицы PizzaCompany, созданной выше.
1 2 3 4 5 6 7 8 7 0 107 002 11 12 13 14 15 16 17 18 | CREATE TABLE [dbo].[Foods] ( [ItemId] INT PRIMARY KEY CLUSTERED , [ItemName] Varchar(50), [UnitsSold7 int 7 int, 2ВНЕШНИЙ КЛЮЧ (CompanyID) ССЫЛКИ PizzaCompany(CompanyID) ) ВСТАВИТЬ В [dbo].[Foods] ([ItemId], [ItemName], [UnitsSold], [CompanyId]) VALUES(1,’Большая пицца’,5, 2) ВСТАВИТЬ В [dbo].[Foods] ([ItemId], [ItemName], [UnitsSold], [CompanyId]) VALUES(2,’чесночные узлы’,6,3) ВСТАВИТЬ В [dbo].[Foods] ([ItemId], [ItemName], [UnitsSold], [CompanyId]) VALUES(3,’Большая пицца’,3,3) ВСТАВИТЬ В [dbo].[ Foods] ([ItemId], [ItemName], [UnitsSold], [CompanyId]) VALUES(4,’Средняя пицца’,8,4) ВСТАВИТЬ В [dbo].[Foods] ([ItemId], [ItemName ], [UnitsSold], [CompanyId]) VALUES(5,’Breadsticks’,7,1) ВСТАВИТЬ В [dbo]. [Foods] ([ItemId], [ItemName], [UnitsSold], [CompanyId]) VALUES(6,’Средняя пицца’,11,1) ВСТАВИТЬ В [dbo].[Foods] ([ItemId], [ItemName], [UnitsSold], [CompanyId]) VALUES(7,’Маленькая пицца’, 9,6) ВСТАВИТЬ В [dbo].[Foods] ([ItemId], [ItemName], [UnitsSold], [CompanyId]) VALUES(8,’Маленькая пицца’,6,7)
SELECT * ИЗ продуктов питания |
В следующей таблице показаны данные из таблицы «Продукты». В этой таблице хранится такая информация, как количество проданных единиц продуктов питания, а также пиццерия (CompanyId), которая ее доставляет.
Теперь, если мы хотим увидеть товары, а также единицы, проданные каждой компанией по производству пиццы, мы можем объединить эти две таблицы с помощью предложения внутреннего соединения, используемого в поле CompanyId (в нашем случае это разделяет отношение внешнего ключа ).
SELECT pz.CompanyCity, pz.CompanyName, pz. CompanyId AS PizzaCompanyId, f.CompanyID AS FoodsCompanyId, f.ItemName, f.UnitsSold ИЗ PizzaCompany pz INNER JOIN Foods f pz.Company ON Идентификатор компании |
Ниже приведен набор результатов приведенного выше запроса внутреннего соединения SQL. Для каждой строки в таблице PizzaCompany функция Inner Join сравнивает и находит совпадающие строки в таблице Foods и возвращает все совпадающие строки, как показано ниже. И если вы заметили, CompanyId = 5 исключается из результата запроса, так как не соответствует таблице Foods.
С помощью приведенного выше набора результатов мы можем разобрать товары, а также количество товаров, доставленных пиццериями в разных городах. Например, компания Dominos доставила в Лос-Анджелес 7 хлебных палочек и 11 средних пицц.
Внутреннее соединение SQL для трех таблиц
Давайте подробнее рассмотрим это объединение и предположим, что в штате откроются три аквапарка (похоже на лето), и эти аквапарки будут брать еду из пиццерий, упомянутых в таблице PizzaCompany.
Я собираюсь быстро создать таблицу WaterPark и загрузить в нее произвольные данные, как показано ниже.
1 2 3 4 5 6 7 8 7 0 107 002 11 12 13 14 | CREATE TABLE [dbo].[WaterPark] ( [WaterParkLocation] VARCHAR(50), [CompanyId] int, FOREIGN KEY(CompanyID) REFERENCES PizzaCompany(CompanyID) ) INSERT INTO [dbo].[WaterPark] ([WaterParkLocation], [CompanyId]) VALUES(‘Street 14 ) INSERT INTO [dbo].[WaterPark] ([WaterParkLocation], [CompanyId]) VALUES(‘Boulevard 2’,2) INSERT INTO [dbo].[WaterPark] ([WaterParkLocation], [CompanyId]) VALUES(‘Rogers 54’,4) INSERT INTO [dbo].[WaterPark] ([WaterParkLocation], [CompanyId]) VALUES(‘Street 14’,3) ВСТАВИТЬ В [dbo].[WaterPark] ([WaterParkLocation], [CompanyId]) VALUES(‘Rogers 54’,5) ВСТАВИТЬ В [dbo]. [WaterPark] ([WaterParkLocation], [CompanyId]) VALUES (‘Бульвар 2’,5)
ВЫБЕРИТЕ * ИЗ Аквапарка |
И ниже вывод этой таблицы.
Как говорится, картинка стоит тысячи слов. Давайте быстро посмотрим на схему базы данных этих трех таблиц с их отношениями, чтобы лучше понять их.
Теперь мы собираемся включить эту третью таблицу в предложение SQL Inner Join, чтобы посмотреть, как это повлияет на набор результатов. Согласно данным в таблице WaterPark, три аквапарка передавали еду от всех пиццерий, кроме Pizzeria (Id = 6) и chuck e cheese (Id = 7). Выполните приведенный ниже код, чтобы увидеть всю раздачу еды в аквапарках по точкам Pizza.
1 2 3 4 5 6 | ВЫБЕРИТЕ pz.CompanyId, pz.CompanyCity, pz.CompanyName,f.ItemName, f.UnitsSold, w.WaterParkLocation ИЗ PizzaCompany pz INNER JOIN Foods f ON pz. 2700CompanyId = f.00002 w.WaterParkLocation ПРИСОЕДИНЯЙТЕСЬ к WaterPark w ON w.CompanyId = pz.CompanyId ЗАКАЗ ПО pz.CompanyId |
На основе CompanyId SQL Inner Join сопоставляет строки в обеих таблицах, PizzaCompany (таблица 1) и Foods (таблица 2), а затем ищет совпадение в WaterPark (таблица 3), чтобы вернуть строки. Как показано ниже, с добавлением внутреннего соединения в WaterPark CompanyId (6,7 (кроме 5)) также исключается из окончательного набора результатов, поскольку условие w.CompanyId = pz.CompanyId не выполняется для идентификаторов (6, 7). Вот как внутреннее соединение SQL помогает возвращать определенные строки данных из нескольких таблиц.
Давайте углубимся в SQL Inner Join еще с несколькими предложениями T-SQL.
Использование WHERE с внутренним соединением
Мы можем фильтровать записи на основе указанного условия, когда внутреннее соединение SQL используется с предложением WHERE. Предположим, что мы хотим получить строки, в которых продано больше 6 единиц.
В следующем запросе добавлено предложение WHERE для извлечения результатов со значением более 6 для проданных единиц.
ВЫБЕРИТЕ pz.CompanyId, pz.CompanyCity, pz.CompanyName,f.ItemName, f.UnitsSold ИЗ PizzaCompany pz INNER JOIN Foods f ON pz.CompanyId = f.CompanyId 9000WHERE f.6 ЗАКАЗАТЬ pz.CompanyCity |
Выполните приведенный выше код в SSMS, чтобы увидеть результат ниже. Этот запрос возвращает четыре таких записи.
Использование Group By с внутренним соединением
SQL Inner Join позволяет нам использовать предложение Group by вместе с агрегатными функциями для группировки результирующего набора по одному или нескольким столбцам. Группировка по обычно работает с внутренним соединением над окончательным результатом, возвращаемым после объединения двух или более таблиц. Если вы не знакомы с предложением Group by в SQL, я бы посоветовал пройти его, чтобы быстро понять эту концепцию. Ниже приведен код, в котором используется предложение Group By с внутренним соединением.
ВЫБЕРИТЕ pz.CompanyCity, pz.CompanyName, SUM(f.UnitsSold) AS TotalQuantitySold FROM PizzaCompany pz INNER JOIN Foods f ON pz.CompanyId = f.CompanyId pz.CompanyName, pz.CompanyName ЗАКАЗАТЬ pz.CompanyCity |
Здесь мы намерены получить общее количество товаров, проданных каждой пиццерией, присутствующей в городе. Как вы можете видеть ниже, совокупный результат в столбце «Общее количество проданных» равен 18 (7+11) и 9.(6+3) для Лос-Анджелеса и Сан-Диего соответственно.
Краткая заметка об Equi и Theta Join
Прежде чем мы закончим эту статью, давайте быстро пробежимся по терминам, которые разработчик SQL может время от времени слышать — Equi и Theta Join.
Equi Join
Как следует из названия, эквивалентное соединение содержит оператор равенства «=» либо в предложении Join, либо в условии WHERE. SQL Inner, Left, Right — все это эквивалентные соединения, когда оператор «=» используется в качестве оператора сравнения. Обычно, когда упоминается внутреннее соединение SQL, оно рассматривается как внутреннее равное соединение, только в необычной ситуации оператор равенства не используется.
Чтобы упростить задачу, я собираюсь обратиться к образцу базы данных AdventureWorksDW2017 и запустить запрос к существующим таблицам, чтобы продемонстрировать, как выглядит эквивалентное соединение.
Select E.employeekey, E.FirstName, E.Title, E.Hiredate, Fs.Salesamountquota от Dememployee E Внутреннее объединение FactSalesquota FS на E.Employekey = fs.Employeekeekey |
Тета-соединение (неэквивалентное соединение)
Соединение без эквивалента в основном противоположно соединению по эквивалентности и используется, когда мы присоединяемся к условию, отличному от оператора «=». Этот тип редко используется на практике. Ниже приведен пример, в котором используется тета-соединение с оператором неравенства (<) для оценки прибыли путем оценки себестоимости и продажных цен в двух таблицах.
SELECT * FROM Table1 T1, Table2 T2 WHERE T1.ProductCost < T2.SalesPrice |
Заключение
Я надеюсь, что эта статья о «Внутреннем соединении SQL» обеспечивает понятный подход к одному из важных и часто используемых предложений — «Внутреннее соединение» в SQL Server для объединения нескольких таблиц. Если у вас есть какие-либо вопросы, пожалуйста, не стесняйтесь задавать их в разделе комментариев ниже.
Чтобы продолжить изучение SQL Joins, вы можете обратиться к следующим сообщениям:
- SQL OUTER JOIN обзор и примеры
- SQL Join введение и обзор
- Автор
- Последние сообщения
Гаури Махаджан
Гаури является специалистом по SQL Server и имеет более чем 6-летний опыт работы с глобальными многонациональными консалтинговыми и технологическими организациями.