Query UNION senza tabella in MS Access (Jet / ACE)

Funziona come previsto:

SELECT "Mike" AS FName 

Ciò non riesce con l’errore “L’input della query deve contenere almeno una tabella o query”:

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

È solo una stranezza / limitazione del motore di database Jet / ACE o mi manca qualcosa?

Non hai trascurato nulla. Il motore di database di accesso consentirà una singola riga SELECT senza un’origine dati FROM . Ma se si desidera UNION o UNION ALL multiple rows, è necessario includere un FROM … anche se non si fa riferimento a nessun campo da tale origine dati.

Ho creato una tabella con una riga e aggiunto un vincolo di controllo per garantire che abbia sempre una sola riga.

 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 

Quella Dual tabella è utile per query come questa:

 SELECT "foo" AS my_text FROM Dual UNION ALL SELECT "bar" FROM Dual; 

Un altro approccio che ho visto è quello di utilizzare un’istruzione SELECT con TOP 1 o una clausola WHERE che limita il set di risultati a una singola riga.

I vincoli di verifica delle note sono stati aggiunti con Jet 4 e sono disponibili solo per le istruzioni eseguite da ADO. CurrentProject.Connection.Execute strSql funziona perché CurrentProject.Connection è un object ADO. Se si tenta di eseguire la stessa istruzione con DAO (ad esempio CurrentDb.Execute o dalla finestra Progettazione query di Access), si verificherà un errore di syntax poiché DAO non è in grado di creare vincoli di controllo.

Se hai accesso ad alcune tabelle di sistema, puoi emulare una doppia tabella in questo modo:

 (SELECT COUNT(*) FROM MSysResources) AS DUAL 

Purtroppo, non sono a conoscenza di tabelle di sistema che …

  • sono sempre disponibili, leggibili (MSysObjects potrebbe non essere accessibile ad ogni connessione)
  • contiene esattamente un record, ad esempio DUAL di Oracle o SYSIBM.DUAL di DB2

Quindi scrivi:

 SELECT 'Mike' AS FName FROM (SELECT COUNT(*) FROM MSysResources) AS DUAL UNION ALL SELECT 'John' AS FName FROM (SELECT COUNT(*) FROM MSysResources) AS DUAL 

Questo è ciò che viene implementato come elemento sintattico in jOOQ , ad esempio.

Quando hai limitato l’accesso di sola lettura al database (cioè non puoi creare nuove tabelle o accedere alle risorse di sistema), questo potrebbe funzionare:

 SELECT "Mike" AS FName FROM (SELECT COUNT(*) FROM anyTable WHERE 1=0) AS dual 
  1. anyTable è la prima tabella utente che trovi (non riesco a immaginare un database reale senza tabella utente!).

  2. DOVE 1 = 0 dovrebbe restituire velocemente un conteggio di 0, anche su un grande tavolo (si spera che il motore Jet sia abbastanza intelligente da riconoscere una condizione così insignificante).

Se qualcuno vuole usare il metodo Top 1, dovrebbe assomigliare a questo:

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

L’alias per il campo deve essere lo stesso su entrambi i lati dell’unione, in questo caso “FName”.

Ecco un modo molto più semplice per farlo:

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

Importante: TableWith1Row può essere una tabella con letteralmente 1 record (che si ignora comunque) OPPURE può essere una tabella con un numero qualsiasi di righe (deve avere almeno 1 riga) ma si aggiunge una clausola WHERE per garantire 1 riga. Questo è un po ‘sciocco, ma è un modo rapido per farlo funzionare senza creare più tabelle.