Подтвердить что ты не робот

Непосредственный запрос UNION в MS Access (Jet/ACE)

Это работает как ожидалось:

SELECT "Mike" AS FName

Это не удается с ошибкой "Ввод запроса должен содержать хотя бы одну таблицу или запрос":

SELECT "Mike" AS FName
UNION ALL
SELECT "John" AS FName

Является ли это просто причудой/ограничением механизма базы данных Jet/ACE или я что-то упускаю?

4b9b3361

Ответ 1

Ты ничего не забыл. Механизм доступа к базе данных допускает одну строку SELECT без источника данных FROM. Но если вы хотите, чтобы UNION или UNION ALL несколько строк, вы должны включить FROM... даже если вы не ссылаетесь на какое-либо поле из этого источника данных.

Я создал таблицу с одной строкой и добавил ограничение проверки, чтобы гарантировать, что она всегда будет иметь одну и только одну строку.

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 (т.е. CurrentDb.Execute или из конструктора запросов Access), вы получите синтаксическую ошибку, поскольку DAO не сможет создать контрольные ограничения.

Ответ 2

Если у вас есть доступ к некоторым системным таблицам, вы можете эмулировать двойную таблицу следующим образом:

(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, например.

Ответ 3

Если вы ограничили доступ только для чтения к базе данных (т.е. вы не можете создавать новые таблицы или получать доступ к системным ресурсам), это может работать:

SELECT "Mike" AS FName
FROM (SELECT COUNT(*) FROM anyTable WHERE 1=0) AS dual
  • anyTable - это первая таблица пользователей, которую вы найдете (я не могу представить себе реальную базу данных без таблицы пользователя!).

  • WHERE 1 = 0 должен возвращать быстрый счет 0, даже на большой таблице (надеюсь, что двигатель Jet достаточно умен, чтобы распознать такое тривиальное условие).

Ответ 4

Если кто-то хочет использовать метод Top 1, он будет выглядеть так:

SELECT first_name AS FName
FROM tblname
UNION ALL
SELECT "Mike" as Fname
FROM (Select Top 1 Count(*) FROM tblsometable);

Псевдоним для поля должен быть одним и тем же с обеих сторон объединения, в данном случае "FName".

Ответ 5

Здесь гораздо более простой способ сделать это:

SELECT 'foo', 'boo', 'hoo' from TableWith1Row
union
SELECT 'foo1', 'boo1', 'hoo1' from TableWith1Row

Важно: TableWith1Row может быть таблицей с буквально 1 записью (которую вы игнорируете в любом случае) ИЛИ она может быть таблицей с любым количеством строк (должна иметь значение AT LEAST 1 row), но вы добавляете предложение WHERE, чтобы обеспечить 1 строку, Это немного бесполезно-goosy, но это быстрый способ сделать эту работу без создания дополнительных таблиц.