Запрос объединения без таблицы в MS Access (Jet/ACE)
это работает так, как ожидалось:
SELECT "Mike" AS FName
это не удается с ошибкой "ввод запроса должен содержать по крайней мере одну таблицу или запрос":
SELECT "Mike" AS FName
UNION ALL
SELECT "John" AS FName
Это просто причуда / ограничение ядра СУБД Jet/ACE или я что-то упускаю?
5 ответов
вы ничего не упустили. СУБД Access, которая позволит одну строку SELECT
без FROM
источник данных. Но если вы хотите UNION
или UNION ALL
несколько строк, вы должны включить FROM
... даже если вы не ссылаетесь на какое-либо поле из этого источника данных.
я создал таблицу с одной строкой и добавить ограничение Check, чтобы гарантировать, что это всегда будет иметь одну и только одну строку.
Public Sub CreateDualTable()
Dim strSql As String
strSql = "CREATE TABLE Dual (id COUNTER CONSTRAINT pkey PRIMARY KEY);"
Debug.Print strSql
CurrentProject.Connection.Execute strSql
strSql = "INSERT INTO Dual (id) VALUES (1);"
Debug.Print strSql
CurrentProject.Connection.Execute strSql
strSql = "ALTER TABLE Dual" & vbNewLine & _
vbTab & "ADD CONSTRAINT there_can_be_only_one" & vbNewLine & _
vbTab & "CHECK (" & vbNewLine & _
vbTab & vbTab & "(SELECT Count(*) FROM Dual) = 1" & vbNewLine & _
vbTab & vbTab & ");"
Debug.Print strSql
CurrentProject.Connection.Execute strSql
End Sub
это Dual
таблица полезна для таких запросов, как это:
SELECT "foo" AS my_text
FROM Dual
UNION ALL
SELECT "bar"
FROM Dual;
другой подход, который я видел, - использовать SELECT
заявление TOP 1
или WHERE
предложение, которое ограничивает результирующий набор одной строкой.
Примечание ограничения проверки были добавлены с помощью Jet 4 и доступны только для операторов, выполняемых из ADO. CurrentProject.Connection.Execute strSql
работает, потому что CurrentProject.Connection
является объектом ADO. Если вы попытаетесь выполнить тот же оператор с DAO (ie CurrentDb.Execute
или из конструктора запросов доступа), вы получите синтаксическую ошибку, потому что DAO не может создание ограничений проверки.
если у вас есть доступ к некоторым системным таблицам, вы можете эмулировать двойной стол таким образом:
(SELECT COUNT(*) FROM MSysResources) AS DUAL
к сожалению, я не знаю о каких-либо системных таблицах...
- всегда доступны, читаемы (MSysObjects может быть доступен не для каждого соединения)
- содержат ровно одну запись, такую как Oracle
DUAL
или DB2 этоSYSIBM.DUAL
так ты пишешь:
SELECT 'Mike' AS FName
FROM (SELECT COUNT(*) FROM MSysResources) AS DUAL
UNION ALL
SELECT 'John' AS FName
FROM (SELECT COUNT(*) FROM MSysResources) AS DUAL
это то, что реализуется в синтаксический элемент jOOQ, например.
когда вы ограничили доступ только для чтения к базе данных (i.e вы не можете создавать новые таблицы или обращаться к системным ресурсам), это может работать:
SELECT "Mike" AS FName
FROM (SELECT COUNT(*) FROM anyTable WHERE 1=0) AS dual
anyTable это первая пользовательская таблица, которую вы найдете (я вряд ли могу представить реальную базу данных без таблицы пользователей!).
где 1=0 предполагается быстро вернуть счет 0, даже на большом столе (надеюсь, реактивный двигатель достаточно умен, чтобы распознать такие тривиальное условие).
вот гораздо более простой способ сделать это:
SELECT 'foo', 'boo', 'hoo' from TableWith1Row
union
SELECT 'foo1', 'boo1', 'hoo1' from TableWith1Row
важно: TableWith1Row может быть либо таблицей с буквально 1 записью (которую вы все равно игнорируете), либо таблицей с любым количеством строк (должна иметь не менее 1 строки), но вы добавляете предложение WHERE, чтобы обеспечить 1 строку. Это немного рыхлый, но это быстрый способ сделать эту работу без создания дополнительных таблиц.
Если кто-то хочет использовать метод Top 1, это будет выглядеть так:
SELECT first_name AS FName
FROM tblname
UNION ALL
SELECT "Mike" as Fname
FROM (Select Top 1 Count(*) FROM tblsometable);
псевдоним для поля должен быть одинаковым с обеих сторон объединения, в данном случае "FName".