web-dev-qa-db-ja.com

MS Access(Jet / ACE)でのテーブルレスUNIONクエリ

これは期待どおりに機能します。

SELECT "Mike" AS FName

これは、「クエリ入力には少なくとも1つのテーブルまたはクエリが含まれている必要があります」というエラーで失敗します。

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

これはJet/ACEデータベースエンジンの癖/制限ですか、それとも何かが足りませんか?

26
mwolfe02

あなたは何も見落としていませんでした。 Accessのデータベースエンジンは、SELECTデータソースなしで単一行FROMを許可します。ただし、複数の行をUNIONまたはUNION ALLする場合は、そのデータソースからフィールドを参照していない場合でも、FROM...を含める必要があります。

1行のテーブルを作成し、チェック制約を追加して、常に1行のみになるようにしました。

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;

私が見たもう1つのアプローチは、SELECTステートメントをTOP 1またはWHERE句とともに使用して、結果セットを1行に制限することです。

チェック制約はJet4で追加され、ADOから実行されたステートメントでのみ使用可能であることに注意してください。 CurrentProject.Connection.Execute strSqlはADOオブジェクトであるため、CurrentProject.Connectionは機能します。DAOで同じステートメントを実行しようとした場合(つまり、CurrentDb.ExecuteまたはAccessクエリデザイナから) 、DAOはチェック制約を作成できないため、構文エラーが発生します。

23
HansUp

一部のシステムテーブルにアクセスできる場合は、次の方法でデュアルテーブルをエミュレートできます。

(SELECT COUNT(*) FROM MSysResources) AS DUAL

残念ながら、私はそのようなシステムテーブルを知りません...

  • 常に利用可能で読み取り可能です(MSysObjectsはすべての接続からアクセスできるとは限りません)
  • oracleのDUALやDB2のSYSIBM.DUALなど、1つのレコードのみが含まれます

だからあなたは書くだろう:

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 で構文要素として実装されているものです。

6
Lukas Eder

データベースへの読み取り専用アクセスを制限している場合(つまり、新しいテーブルを作成したり、システムリソースにアクセスしたりできない場合)、これは機能する可能性があります。

SELECT "Mike" AS FName
FROM (SELECT COUNT(*) FROM anyTable WHERE 1=0) AS dual
  1. anyTableは、最初に見つけたユーザーテーブルです(ユーザーテーブルのない実際のデータベースはほとんど想像できません!)。

  2. WHERE 1 =は、大きなテーブルであっても、0のカウントを高速で返すことになっています(Jetエンジンがそのような些細な状態を認識するのに十分スマートであることを願っています)。

2
Cristi S.

これを行うためのはるかに簡単な方法は次のとおりです。

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

重要:TableWith1Rowは、文字通り1つのレコードを持つテーブルにすることができます(とにかく無視します)OR任意の数の行を持つテーブルにすることができます(AT = LEAST 1 row)ただし、WHERE句を追加して、1行を確保します。これは少しお粗末ですが、テーブルを追加せずにこれを機能させる簡単な方法です。

1
HerrimanCoder

テーブル名を入力します(実際にテーブルから列を選択する必要はありません)。

このクエリは、ドロップダウンに必要な3会計年度を示します。会計年度は7月に始まります。

SELECT IIf(Month(Now())>6,Year(Now())-1,Year(Now())-2) AS FY
FROM table
UNION 
SELECT IIf(Month(Now())>6,Year(Now()),Year(Now())-1) AS FY
FROM table
UNION 
SELECT IIf(Month(Now())>6,Year(Now())+1,Year(Now())) AS FY
FROM table;
0
David Morr

トップ1の方法を使用したい場合は、次のようになります。

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

フィールドのエイリアスは、ユニオンの両側で同じである必要があります。この場合は「FName」です。

0
guest