Интересуют операции с множествами. Есть такой код: [vba]
Код
' Объединить Sub Union() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] UNION SELECT * FROM [Лист1$B1:B5];") Range("D1").CopyFromRecordset ADO.Recordset End Sub
' Объединить все Sub UnionAll() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] UNION ALL SELECT * FROM [Лист1$B1:B5];") Range("F1").CopyFromRecordset ADO.Recordset End Sub
' Пересечение Sub Intersect() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] INTERSECT SELECT * FROM [Лист1$B1:B5];") Range("H1").CopyFromRecordset ADO.Recordset End Sub
' Разность Sub Except() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] EXCEPT SELECT * FROM [Лист1$B1:B5];") Range("J1").CopyFromRecordset ADO.Recordset End Sub
' Разность все Sub ExceptAll() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] EXCEPT ALL SELECT * FROM [Лист1$B1:B5];") Range("L1").CopyFromRecordset ADO.Recordset End Sub
[/vba] Корректно отрабатывают только операции объединения UNION и UNION ALL. Интересует, можно ли эмулировать остальные операции в sql excel?
Спасибо.
Всем привет
Интересуют операции с множествами. Есть такой код: [vba]
Код
' Объединить Sub Union() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] UNION SELECT * FROM [Лист1$B1:B5];") Range("D1").CopyFromRecordset ADO.Recordset End Sub
' Объединить все Sub UnionAll() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] UNION ALL SELECT * FROM [Лист1$B1:B5];") Range("F1").CopyFromRecordset ADO.Recordset End Sub
' Пересечение Sub Intersect() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] INTERSECT SELECT * FROM [Лист1$B1:B5];") Range("H1").CopyFromRecordset ADO.Recordset End Sub
' Разность Sub Except() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] EXCEPT SELECT * FROM [Лист1$B1:B5];") Range("J1").CopyFromRecordset ADO.Recordset End Sub
' Разность все Sub ExceptAll() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] EXCEPT ALL SELECT * FROM [Лист1$B1:B5];") Range("L1").CopyFromRecordset ADO.Recordset End Sub
[/vba] Корректно отрабатывают только операции объединения UNION и UNION ALL. Интересует, можно ли эмулировать остальные операции в sql excel?
' Объединить Sub Union() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] UNION SELECT * FROM [Лист1$B1:B5];") Range("D1").CopyFromRecordset ADO.Recordset End Sub
' Объединить все Sub UnionAll() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] UNION ALL SELECT * FROM [Лист1$B1:B5];") Range("F1").CopyFromRecordset ADO.Recordset End Sub
' Пересечение Sub Intersect() Dim ADO As New ADO ADO.Query ("SELECT [Лист1$A1:A9].F1 FROM [Лист1$A1:A9] left join [Лист1$B1:B5] on [Лист1$A1:A9].[F1] = [Лист1$B1:B5].[F1] where [Лист1$B1:B5].[F1] is not null;") Range("H1").CopyFromRecordset ADO.Recordset End Sub
' Разность Sub Except() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] left join [Лист1$B1:B5] on [Лист1$A1:A9].[F1] = [Лист1$B1:B5].[F1] where [Лист1$B1:B5].[F1] is null;") Range("J1").CopyFromRecordset ADO.Recordset End Sub
' Разность все Sub ExceptAll() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] left join [Лист1$B1:B5] on [Лист1$A1:A9].[F1] = [Лист1$B1:B5].[F1] where [Лист1$B1:B5].[F1] is null " & _ " union " & _ "SELECT * FROM [Лист1$B1:B5] left join [Лист1$A1:A9] on [Лист1$B1:B5].[F1] = [Лист1$A1:A9].[F1] where [Лист1$A1:A9].[F1] is null ;") Range("L1").CopyFromRecordset ADO.Recordset End Sub
[/vba]
Если вот так попробовать? [vba]
Код
' Объединить Sub Union() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] UNION SELECT * FROM [Лист1$B1:B5];") Range("D1").CopyFromRecordset ADO.Recordset End Sub
' Объединить все Sub UnionAll() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] UNION ALL SELECT * FROM [Лист1$B1:B5];") Range("F1").CopyFromRecordset ADO.Recordset End Sub
' Пересечение Sub Intersect() Dim ADO As New ADO ADO.Query ("SELECT [Лист1$A1:A9].F1 FROM [Лист1$A1:A9] left join [Лист1$B1:B5] on [Лист1$A1:A9].[F1] = [Лист1$B1:B5].[F1] where [Лист1$B1:B5].[F1] is not null;") Range("H1").CopyFromRecordset ADO.Recordset End Sub
' Разность Sub Except() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] left join [Лист1$B1:B5] on [Лист1$A1:A9].[F1] = [Лист1$B1:B5].[F1] where [Лист1$B1:B5].[F1] is null;") Range("J1").CopyFromRecordset ADO.Recordset End Sub
' Разность все Sub ExceptAll() Dim ADO As New ADO ADO.Query ("SELECT * FROM [Лист1$A1:A9] left join [Лист1$B1:B5] on [Лист1$A1:A9].[F1] = [Лист1$B1:B5].[F1] where [Лист1$B1:B5].[F1] is null " & _ " union " & _ "SELECT * FROM [Лист1$B1:B5] left join [Лист1$A1:A9] on [Лист1$B1:B5].[F1] = [Лист1$A1:A9].[F1] where [Лист1$A1:A9].[F1] is null ;") Range("L1").CopyFromRecordset ADO.Recordset End Sub
' Пересечение Sub Intersect() Dim ADO As New ADO ADO.Query ("SELECT [Лист1$A1:A9].F1 FROM [Лист1$A1:A9] left join [Лист1$B1:B5] on [Лист1$A1:A9].[F1] = [Лист1$B1:B5].[F1] where [Лист1$B1:B5].[F1] is not null;") Range("H1").CopyFromRecordset ADO.Recordset End Sub
Здесь можно попроще - с INNER JOIN и без WHERE: [vba]
Код
ADO.Query "SELECT a.F1 FROM [Лист1$A1:A9] a INNER JOIN [Лист1$B1:B5] b ON a.F1 = b.F1"
[/vba]
Цитата (M73568)
' Пересечение Sub Intersect() Dim ADO As New ADO ADO.Query ("SELECT [Лист1$A1:A9].F1 FROM [Лист1$A1:A9] left join [Лист1$B1:B5] on [Лист1$A1:A9].[F1] = [Лист1$B1:B5].[F1] where [Лист1$B1:B5].[F1] is not null;") Range("H1").CopyFromRecordset ADO.Recordset End Sub
Здесь можно попроще - с INNER JOIN и без WHERE: [vba]
Код
ADO.Query "SELECT a.F1 FROM [Лист1$A1:A9] a INNER JOIN [Лист1$B1:B5] b ON a.F1 = b.F1"
Ну, у меня не ругалось. Вроде, в Jet'е для псевдонимов таблиц он необязателен, а для псевдонимов полей - обязателен. Короче, я всегда экпериментально проверяю конкретные случаи
Цитата (ikki)
AS не нужен?
Ну, у меня не ругалось. Вроде, в Jet'е для псевдонимов таблиц он необязателен, а для псевдонимов полей - обязателен. Короче, я всегда экпериментально проверяю конкретные случаи Gustav
потому что в первом is not null, а во втором - is null.
Цитата (nerv)
как работает LEFT JOIN
Сначала отбирает все записи из левой таблицы (во временный набор), потом приставляет к ним (в этом временном наборе) совпадающие записи из правой таблицы (совпадающие - по связующему полю ON...). Там, где совпадений не находится, справа (во временном наборе) ставится null. Далее, чтобы найти записи левой таблицы, не имеющие связи с правой таблицей, просто выбираем те записи, у которых справа null.
Цитата (nerv)
не одно и тоже?
одно и то же
Цитата (nerv)
результат работы разный
потому что в первом is not null, а во втором - is null.
Цитата (nerv)
как работает LEFT JOIN
Сначала отбирает все записи из левой таблицы (во временный набор), потом приставляет к ним (в этом временном наборе) совпадающие записи из правой таблицы (совпадающие - по связующему полю ON...). Там, где совпадений не находится, справа (во временном наборе) ставится null. Далее, чтобы найти записи левой таблицы, не имеющие связи с правой таблицей, просто выбираем те записи, у которых справа null.Gustav
Я просто привык писать левые джойны, inner практически редко использую (right join только когда лень переписать left join), тем более что можно обойтись простым = [vba]
Код
ADO.Query "SELECT a.F1 FROM [Лист1$A1:A9] a, [Лист1$B1:B5] b where a.F1 = b.F1"
[/vba] Тоже самое только порядок сортировки по правой таблице, но что мешает добавить ORDER BY a.F1
Цитата (nerv)
Хотя инет говорит, что в SQL тоже есть циклы...
ЕМНИП циклы это больше для хранимых процедур, триггеров... в тот же Aссess их уже не вставишь
Цитата (Gustav)
Здесь можно попроще - с INNER JOIN и без WHERE:
Я просто привык писать левые джойны, inner практически редко использую (right join только когда лень переписать left join), тем более что можно обойтись простым = [vba]
Код
ADO.Query "SELECT a.F1 FROM [Лист1$A1:A9] a, [Лист1$B1:B5] b where a.F1 = b.F1"
[/vba] Тоже самое только порядок сортировки по правой таблице, но что мешает добавить ORDER BY a.F1
Цитата (nerv)
Хотя инет говорит, что в SQL тоже есть циклы...
ЕМНИП циклы это больше для хранимых процедур, триггеров... в тот же Aссess их уже не вставишьM73568
RIGHT JOIN я использую обычно по "концептуальным соображениям", т.е., например, когда сравниваются две таблицы, то делаю:
1. Общие записи с INNER JOIN. 2. Записи, встречающиеся только в первой ("левой") таблице - LEFT JOIN с null в "правой". 3. Записи, встречающиеся только во второй ("правой") таблице - RIGHT JOIN с null в "левой". Это можно написать и с LEFT JOIN, но тогда придется менять местами таблицы в тексте запроса.
Хотя, в общем, RIGHT JOIN это некоторое косметическое излишество. Некоторые системы прекрасно обходятся и без него, например, в так называемом Open SQL в SAP есть только INNER и LEFT.
Цитата (M73568)
SELECT a.F1 FROM [Лист1$A1:A9] a, [Лист1$B1:B5] b where a.F1 = b.F1
Так любит писать большинство программистов с большим опытом в больших системах типа Oracle. Особенно когда это нужно писать самому своими ручками. Тексты запросов, автоматически генерируемых в Access по QBE, исторически строятся с использованием JOIN. Собственно, и стандарт ANSI с некоторых пор рекомендует связи между таблицами помещать в JOIN, а все остальные условия - в WHERE. Но так хочется лениться и обходиться только секцией WHERE...
Цитата (M73568)
right join только когда лень переписать left join
RIGHT JOIN я использую обычно по "концептуальным соображениям", т.е., например, когда сравниваются две таблицы, то делаю:
1. Общие записи с INNER JOIN. 2. Записи, встречающиеся только в первой ("левой") таблице - LEFT JOIN с null в "правой". 3. Записи, встречающиеся только во второй ("правой") таблице - RIGHT JOIN с null в "левой". Это можно написать и с LEFT JOIN, но тогда придется менять местами таблицы в тексте запроса.
Хотя, в общем, RIGHT JOIN это некоторое косметическое излишество. Некоторые системы прекрасно обходятся и без него, например, в так называемом Open SQL в SAP есть только INNER и LEFT.
Цитата (M73568)
SELECT a.F1 FROM [Лист1$A1:A9] a, [Лист1$B1:B5] b where a.F1 = b.F1
Так любит писать большинство программистов с большим опытом в больших системах типа Oracle. Особенно когда это нужно писать самому своими ручками. Тексты запросов, автоматически генерируемых в Access по QBE, исторически строятся с использованием JOIN. Собственно, и стандарт ANSI с некоторых пор рекомендует связи между таблицами помещать в JOIN, а все остальные условия - в WHERE. Но так хочется лениться и обходиться только секцией WHERE... Gustav
Существует классический SQL, в котором создается запрос и получается результат (ответ на запрос). С точки зрения наблюдателя (программиста) запрос это некий текст на формальном языке, который, будучи (каким-то образом, сейчас неважно каким) отправленным на выполнение, возвращает плоский набор данных (таблицу).
Для СУБД, которая выполняет запрос, его текст является командой. В процессе ее исполнения СУБД сама, незаметно для нас, осуществляет и циклы, и промежуточные хранения данных, и сортировку по Кнуту методом какого-нибудь пузырька и еще кучу всяких добрых дел. Мы от всего этого абстрагированы, просто в это время сидим, курим бамбук и ждём ответа на свой вопрос-запрос.
Не будь SQLя, мы бы все эти циклы и т.п. писали бы САМИ, как писали когда-то в эпоху Клиппера и первых версий dBase (если не еще "хуже", в смысле более подробно без специальных команд работы с данными).
И хотя "одним запросом" (а они могут быть невероятно сложные - у меня в Oracle бывали под 60K текста), можно сделать многое, но далеко не всё. К тому же, с увеличением сложности запроса затраты на его сопровождение возрастают в квадрате (говорю по собственному опыту).
С целью преодоления этих трудностей и были разработаны процедурные расширения SQL - специальные языки программирования, способные связать операции над множествами с обычными процедурными ("шаг за шагом") элементами программирования (циклами, условиями и т.п.), например, язык PL/SQL в Oracle или Transact-SQL в MS SQL Server.
А для неспецифических языков, например, для нашего любимого VBA, стали разрабатывать специальные библиотеки типа DAO или ADO. Поэтому на VBA мы теперь можем решать вполне SQL-ные задачи не хуже, чем на Transact-SQL.
Цитата (nerv)
Хотя инет говорит, что в SQL тоже есть циклы...
Дело обстоит примерно так.
Существует классический SQL, в котором создается запрос и получается результат (ответ на запрос). С точки зрения наблюдателя (программиста) запрос это некий текст на формальном языке, который, будучи (каким-то образом, сейчас неважно каким) отправленным на выполнение, возвращает плоский набор данных (таблицу).
Для СУБД, которая выполняет запрос, его текст является командой. В процессе ее исполнения СУБД сама, незаметно для нас, осуществляет и циклы, и промежуточные хранения данных, и сортировку по Кнуту методом какого-нибудь пузырька и еще кучу всяких добрых дел. Мы от всего этого абстрагированы, просто в это время сидим, курим бамбук и ждём ответа на свой вопрос-запрос.
Не будь SQLя, мы бы все эти циклы и т.п. писали бы САМИ, как писали когда-то в эпоху Клиппера и первых версий dBase (если не еще "хуже", в смысле более подробно без специальных команд работы с данными).
И хотя "одним запросом" (а они могут быть невероятно сложные - у меня в Oracle бывали под 60K текста), можно сделать многое, но далеко не всё. К тому же, с увеличением сложности запроса затраты на его сопровождение возрастают в квадрате (говорю по собственному опыту).
С целью преодоления этих трудностей и были разработаны процедурные расширения SQL - специальные языки программирования, способные связать операции над множествами с обычными процедурными ("шаг за шагом") элементами программирования (циклами, условиями и т.п.), например, язык PL/SQL в Oracle или Transact-SQL в MS SQL Server.
А для неспецифических языков, например, для нашего любимого VBA, стали разрабатывать специальные библиотеки типа DAO или ADO. Поэтому на VBA мы теперь можем решать вполне SQL-ные задачи не хуже, чем на Transact-SQL.Gustav
Gustav, форум не дает пока репутацию изменить. В любом случае спасибо
Цитата (Gustav)
В процессе ее исполнения СУБД сама, незаметно для нас, осуществляет и циклы, и промежуточные хранения данных, и сортировку по Кнуту методом какого-нибудь пузырька и еще кучу всяких добрых дел
это понятно )
вся прелесть в том, что
Цитата (Gustav)
Мы от всего этого абстрагированы, просто в это время сидим, курим бамбук и ждём ответа на свой вопрос-запрос
именно поэтому мне интересен SQL Я и класс для себя (и всех желающих) запилил, чтобы проще было работать (абстрагироваться от создать объект connection, соединиться, разъединиться и т.п.)
Цитата (Gustav)
Не будь SQLя, мы бы все эти циклы и т.п. писали бы САМИ
согласен. За себя скажу: достаточно много задач приходится решать с "массивами данных". Многие из них сводятся к "элементарным" операциях с множествами, о кот. я спрашивал выше. Т.о.. вместо того, чтобы писать много кода под каждую задачу, мне (надеюсь) будет проще подключить класс и правильно составить SQL запрос. Также не забываем, что ADO/DAO и еже с ним, позволяет работать с закрытыми(!) книгами, что вдвойне приятно
Цитата (Gustav)
И хотя "одним запросом" можно сделать многое, но далеко не всё. К тому же, с увеличением сложности запроса затраты на его сопровождение возрастают в квадрате.
Верю Поэтому, по возможности стараюсь решать задачи поэтапно: запрос - результат (выгрузка на лист). Запрос к результату выгрузки. В большинстве случаев это допустимо. Кроме того, с помощью упомянутого мною ранее класса это довольно просто и понятно выглядит (как мне кажется).
Цитата (Gustav)
или Transact-SQL в MS SQL Server
ага, я его вчера загугливал
И все-таки хотелось бы увидеть пример (желательно простой) и решение задачи , где могут потребоваться циклы в SQL.
Думаю, немного позднее создам тему: "Задачи и решения" применительно к SQL в Эксель.
Gustav, форум не дает пока репутацию изменить. В любом случае спасибо
Цитата (Gustav)
В процессе ее исполнения СУБД сама, незаметно для нас, осуществляет и циклы, и промежуточные хранения данных, и сортировку по Кнуту методом какого-нибудь пузырька и еще кучу всяких добрых дел
это понятно )
вся прелесть в том, что
Цитата (Gustav)
Мы от всего этого абстрагированы, просто в это время сидим, курим бамбук и ждём ответа на свой вопрос-запрос
именно поэтому мне интересен SQL Я и класс для себя (и всех желающих) запилил, чтобы проще было работать (абстрагироваться от создать объект connection, соединиться, разъединиться и т.п.)
Цитата (Gustav)
Не будь SQLя, мы бы все эти циклы и т.п. писали бы САМИ
согласен. За себя скажу: достаточно много задач приходится решать с "массивами данных". Многие из них сводятся к "элементарным" операциях с множествами, о кот. я спрашивал выше. Т.о.. вместо того, чтобы писать много кода под каждую задачу, мне (надеюсь) будет проще подключить класс и правильно составить SQL запрос. Также не забываем, что ADO/DAO и еже с ним, позволяет работать с закрытыми(!) книгами, что вдвойне приятно
Цитата (Gustav)
И хотя "одним запросом" можно сделать многое, но далеко не всё. К тому же, с увеличением сложности запроса затраты на его сопровождение возрастают в квадрате.
Верю Поэтому, по возможности стараюсь решать задачи поэтапно: запрос - результат (выгрузка на лист). Запрос к результату выгрузки. В большинстве случаев это допустимо. Кроме того, с помощью упомянутого мною ранее класса это довольно просто и понятно выглядит (как мне кажется).
Цитата (Gustav)
или Transact-SQL в MS SQL Server
ага, я его вчера загугливал
И все-таки хотелось бы увидеть пример (желательно простой) и решение задачи , где могут потребоваться циклы в SQL.
Думаю, немного позднее создам тему: "Задачи и решения" применительно к SQL в Эксель.nerv
Чебурашка стал символом олимпийских игр. А чего достиг ты? Тишина - самый громкий звук
Может кого-то заинтересует ссылочка на эту тему: http://support.microsoft.com/kb/257819/ru И еще есть файл-справка по ADO (для vba) - если кому-то интересно, могу скинуть (спасибо Р Дмитрию за файл)
Может кого-то заинтересует ссылочка на эту тему: http://support.microsoft.com/kb/257819/ru И еще есть файл-справка по ADO (для vba) - если кому-то интересно, могу скинуть (спасибо Р Дмитрию за файл) LightZ
В Jet SQL мне нравится возможность последующего использования в одной строке результатов уже выполненных вычислений в этой же строке, т.е. практически как формулы в самом Excel. В явном виде описания этой фичи в документации я не встречал.
Чтобы было понятно о чём я, приведу такой пример, возвращающий в E1:G1 три значения 10, 15 и 25: [vba]
Код
Sub Example2() Dim ADO As New ADO
ADO.Query "SELECT a, a + 5 AS d, a + d AS e FROM " & _ "(" & _ "SELECT 10 AS a, 20 AS b, 30 AS c FROM [Лист1$A1:A1]" & _ ")"
Range("E1").CopyFromRecordset ADO.Recordset ADO.Disconnect End Sub
[/vba]
А вот "большой взрослый" Oracle аналогичный запрос не выполнит: [vba]
Код
SELECT a, a + 5 AS d, a + d AS e FROM ( SELECT 10 AS a, 20 AS b, 30 AS c FROM dual )
[/vba]
А выполнит только вот такой, когда вычисление d выполняется на промежуточном этапе: [vba]
Код
SELECT a, d, a + d AS e FROM ( SELECT a, a + 5 AS d FROM ( SELECT 10 AS a, 20 AS b, 30 AS c FROM dual ))
[/vba]
В Jet SQL мне нравится возможность последующего использования в одной строке результатов уже выполненных вычислений в этой же строке, т.е. практически как формулы в самом Excel. В явном виде описания этой фичи в документации я не встречал.
Чтобы было понятно о чём я, приведу такой пример, возвращающий в E1:G1 три значения 10, 15 и 25: [vba]
Код
Sub Example2() Dim ADO As New ADO
ADO.Query "SELECT a, a + 5 AS d, a + d AS e FROM " & _ "(" & _ "SELECT 10 AS a, 20 AS b, 30 AS c FROM [Лист1$A1:A1]" & _ ")"
Range("E1").CopyFromRecordset ADO.Recordset ADO.Disconnect End Sub
[/vba]
А вот "большой взрослый" Oracle аналогичный запрос не выполнит: [vba]
Код
SELECT a, a + 5 AS d, a + d AS e FROM ( SELECT 10 AS a, 20 AS b, 30 AS c FROM dual )
[/vba]
А выполнит только вот такой, когда вычисление d выполняется на промежуточном этапе: [vba]
Код
SELECT a, d, a + d AS e FROM ( SELECT a, a + 5 AS d FROM ( SELECT 10 AS a, 20 AS b, 30 AS c FROM dual ))