Запрос объединения без таблицы в 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
  1. anyTable это первая пользовательская таблица, которую вы найдете (я вряд ли могу представить реальную базу данных без таблицы пользователей!).

  2. где 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".