SELECT
指定された情報をデータベースから取り出します。SELECT ステートメントにより、テンポラリ ビューを作成します。
構文
クエリ スペック ::= (クエリ スペック)
FROM テーブル参照[, テーブル参照]...
[WHERE 検索条件]
order-by式 ::=
式 [
CASE(文字列) |
COLLATE コレーション名]
[ASC | DESC]
選択リスト ::= * | 選択項目[, 選択項目]...
選択項目 ::=
式 [[
AS]
エイリアス名] |
テーブル名. *
テーブル参照 ::= {OJ 外部結合の定義}
| [
データベース名.]
テーブル名 [[
AS]
エイリアス名] [
WITH (
テーブル ヒント)]
| [
データベース名.]
ビュー名 [[
AS]
エイリアス名]
| dbo.f
システム カタログ関数名 [[
AS]
エイリアス名]
| 結合定義
| ( 結合定義)
| (
テーブルサブクエリ) [
AS]
エイリアス名 [(
列名[,
列名]...)]
外部結合の定義 ::= テーブル参照 外部結合タイプ JOIN テーブル参照
ON 検索条件
外部結合タイプ ::= LEFT [OUTER] | RIGHT [OUTER] | FULL [OUTER]
テーブル ヒント ::= INDEX (インデックス値[, インデックス値]...)
インデックス値 ::= 0 | インデックス名
インデックス名 ::= ユーザー定義名
結合定義 ::= テーブル参照 [結合タイプ] JOIN テーブル参照 ON 検索条件
| テーブル参照 CROSS JOIN テーブル参照
| 外部結合の定義
結合タイプ ::= INNER | LEFT [OUTER] | RIGHT [OUTER] |
FULL [OUTER]
テーブル サブクエリ ::=
クエリ スペック [[
UNION [
ALL]
クエリ スペック]...][
ORDER BY order-by式[,
order-by式]...]
検索条件 ::= 検索条件 AND 検索条件
| 検索条件 OR 検索条件
| ( 検索条件)
| 述部
述部 ::=
式 [
NOT]
BETWEEN 式 AND 式 | 式またはサブクエリ 比較演算子 式またはサブクエリ
比較演算子 ::= < | > | <= | >= | = | <> | !=
式またはサブクエリ ::= 式 | (クエリ スペック)
式 ::= 式 - 式
| 式 + 式
| 式 * 式
| 式 / 式
| 式 & 式
| 式 | 式
| 式 ^ 式
| ( 式)
| -式
| +式
| 列名
| ?
| リテラル
| セット関数
| スカラー関数
| {fn スカラー関数}
| CASE case値式 WHEN when式 THEN then式[...] [ELSE else式] END
| SQLSTATE
| サブクエリ式
| NULL
| : ユーザー定義名
| @:IDENTITY
| @:ROWCOUNT
| @@IDENTITY
| @@ROWCOUNT
| @@SPID
case値式 when式,
then式 else式 ::=
CASE(式)を参照
サブクエリ式 ::= (クエリ スペック)
セット関数 ::= COUNT (*)
|
COUNT ([
DISTINCT |
ALL]
式)
|
SUM ([
DISTINCT |
ALL]
式)
|
AVG ([
DISTINCT |
ALL]
式)
|
MIN ([
DISTINCT |
ALL]
式)
|
MAX ([
DISTINCT |
ALL]
式)
|
STDEV ([
DISTINCT |
ALL]
式)
備考
ここでは、以下の項目について説明します。
FOR UPDATE
SELECT FOR UPDATE は、クエリで選択されたテーブル内の 1 つまたは複数の行をロックします。レコード ロックは、次の COMMIT または ROLLBACK ステートメントが発行されたときに解放されます。
この競合を避けるため、SELECT FOR UPDATE は行を取得しているときロックします。
ステートメント レベル SQL_ATTR_CONCURRENCY が SQL_CONCUR_LOCK に設定されている場合、SELECT FOR UPDATE はトランザクション内で優先されます。SQL_ATTR_CONCURRENCY が SQL_CONCUR_READ_ONLY に設定されている場合、データベース エンジンはエラーを返しません。
SELECT FOR UPDATE は WAIT および NOWAIT キーワードをサポートしません。SELECT FOR UPDATE は、短時間で行をロックできない場合(20 回再試行)、ステータス コード
84:レコードまたはページはロックされています。 を返します。
制約
SELECT FOR UPDATE ステートメントには以下の制約があります。
•トランザクション内のみで有効です。トランザクション外で使用された場合、そのステートメントは無視されます。
•単一のテーブルのみでサポートされます。SELECT FOR UPDATE は、JOIN や単純でないビュー、また、GROUP BY、DISTINCT、UNION キーワードと共には使用できません。
•CREATE VIEW ステートメント内では使用できません。
メモ: SELECT FOR UPDATE をストアド プロシージャの外部で使用する場合は、まず SQLSetConnectOption または SQLSetConnectAttr に SQL_AUTOCOMMIT_OFF 属性を指定する必要があります。
GROUP BY
Pervasive PSQL では、列リストの
GROUP BY がサポートされているほか、式リストやあらゆる式の
GROUP BY もサポートするように、
GROUP BY 式リストの構文が拡張されています。
GROUP BY 拡張の詳細については、
GROUP BY を参照してください。
GROUP BY のない
HAVING はサポートされていません。
以下に示す特性のうちいくつかを持つ SELECT ステートメントの実行によって生成された結果セットおよびストアド ビューは、読み取り専用になります(更新できません)。つまり、結果セットあるいはストアド ビューで位置付け UPDATE、位置付け DELETE、および SQLSetPos を呼び出してデータを追加、変更、削除することは許可されません。
•SQLSetStmtOption で SQL_CONCURRENCY 型に SQL_CONCUR_READ_ONLY を指定した
•選択リストに集計を含んでいる
SELECT SUM(c1) FROM t1
•選択リストに DISTINCT を指定している
SELECT DISTINCT c1 FROM t1
•ビューに GROUP BY 句を含んでいる
SELECT SUM(c1), c2 FROM t1 GROUP BY c2
•ビューは結合である(複数のテーブルを参照する)
SELECT * FROM t1, t2
•ビューに UNION 演算子を使用しており、UNION ALL が指定されていないか、もしくはすべての SELECT ステートメントが同じテーブルを参照していない
SELECT c1 FROM t1 UNION SELECT c1 FROM t1
SELECT c1 FROM t1 UNION ALL SELECT c1 FROM t2
•ストアド ビューでは UNION 演算子を使用できないので注意してください。
•ビューに、外部クエリ内のテーブル以外のテーブルを参照するサブクエリを含んでいる
SELECT c1 FROM t1 WHERE c1 IN (SELECT c1 FROM t2)
動的パラメーター(?)は、SELECT 項目としてはサポートされていません。動的パラメーターが述部の一部であれば、SELECT ステートメント内で使用することができます。たとえば、SELECT * FROM faculty WHERE id = ? は、動的パラメーターが述部の一部なので有効です。
SQLExecDirect ステートメントは動的パラメーターの使用をサポートしていないので注意してください。このことから、SQL Editor を使用して、述部に動的パラメーターを含む SQL ステートメントの実行はできません(SQL Editor は SQLExecDirect を使用します)。
変数は、ストアド プロシージャ内でのみ SELECT 項目として使用することができます。
CREATE PROCEDURE を参照してください。
エイリアスの使用
WHERE、HAVING、ORDER BY、または GROUP BY 句にエイリアスを含めることができます。エイリアス名はテーブル内のどの列名とも異なっていなければなりません。次のステートメントは、WHERE 句と GROUP BY 句でエイリアス "a" および "b" を使用する例を示しています。
SELECT Student_ID a, Transaction_Number b, SUM (Amount_Owed) FROM Billing WHERE a < 120492810 GROUP BY a, b UNION SELECT Student_ID a, Transaction_Number b, SUM (Amount_Paid) FROM Billing WHERE a > 888888888 GROUP BY a, b
SUM と DECIMAL の精度
SUM 集計関数を使って DECIMAL 型のフィールドを集計する場合は、次の規則が適用されます。
結果の有効桁数は 74 ですが、小数部桁数は列定義に依存します。
74 を超える桁数の数値(本当に、非常に大きな数値です)が計算された場合、結果でオーバーフロー エラーが発生することがあります。オーバーフローが発生した場合、値は返らず、SQLSTATE に数値が範囲外であることを示す 22003 が設定されます。
サブクエリ
サブクエリは一種の SELECT ステートメントで、ステートメント内に 1 つ以上の SELECT ステートメントを含んでいます。サブクエリは、ステートメントの処理を進めるために値を生成します。一番上の SELECT ステートメントでサブクエリをネストできる最大数は 16 です。
サポートされるサブクエリのタイプは次のとおりです。
•comparison
•quantified
•in
•exists
•correlated
•expression
•table
メモ: ORDER BY 句は、テーブル サブクエリ内でのみ許可されます。その他の種類のサブクエリ句では許可されません。
HAVING 句の中では、グループ化列への参照を含む相関サブクエリ述部はサポートされていません。
expression サブクエリは、SELECT リストの中でサブクエリを使用できます。たとえば、SELECT (SELECT SUM(c1) FROM t1 WHERE t1.c2 = t1.(c2) FROM t2 のように記述できます。サブクエリの SELECT リストに指定できる項目は 1 つのみです。たとえば、次のステートメントは、サブクエリの SELECT リストに 2 つ以上の項目が含まれているため、エラーが返ります。
SELECT p.id, (SELECT SUM(b.amount_owed), SUM(b.amount_paid) FROM billing b) FROM person p
式としてのサブクエリは相関でも非相関でもかまいません。相関サブクエリは、一番上のステートメントに指定されているテーブル内の 1 つ以上の列を参照します。非相関サブクエリは、一番上のステートメントに指定されているテーブル内の列を参照しません。
WHERE 句の相関サブクエリの例を、次に示します。
SELECT * FROM student s WHERE s.Tuition_id IN
(SELECT t.ID FROM tuition t WHERE t.ID = s.Tuition_ID);
メモ: 相関サブクエリは、テーブル サブクエリでは使用できません。テーブル サブクエリでは非相関サブクエリのみが使用できます。
演算子
IN、
EXISTS、
ALL、または
ANY と関連付けられているサブクエリは式と見なされません。
相関および非相関のサブクエリは、どちらも単一の値のみ返すことができます。このため、相関サブクエリおよび非相関サブクエリはスカラー サブクエリとも呼ばれます。
スカラー サブクエリは、DISTINCT、GROUP BY、および ORDER BY 句に含むことができます。
サブクエリは式の左辺で使用することができます。
式またはサブクエリ 比較演算子 式またはサブクエリ
ここで、式は 1 つの式、比較演算子は次のうちのいずれかです。
< (より小さい) | > (より大きい) | <= (小さいかまたは等しい) | >= (大きいかまたは等しい) | = (等しい) |
<> (等しくない) | != (等しくない) | LIKE | IN | NOT IN |
最適化
左辺のサブクエリの動作は、サブクエリが相関サブクエリでなく、すべての結合条件が 1 つの外部結合である場合の、IN、NOT IN、および =ANY について最適化されています。それ以外の条件は最適化されないことがあります。次は、これらの条件を満たすクエリの例です。
SELECT count(*) FROM person WHERE id IN (SELECT faculty_id FROM class)
Pervasive PSQL はインデックスに基づいてサブクエリを最適化するため、サブクエリでインデックスを使用するとパフォーマンスが向上します。たとえば、次のステートメント内のサブクエリは、student_id が Billing テーブルのインデックスであるため、この列によって最適化されます。
SELECT (SELECT SUM(b.amount_owed) FROM billing b WHERE b.student_id = p.id) FROM person p
サブクエリ内の UNION
1 つのサブクエリの中で、複数の異なる UNION グループをかっこで囲むことは許可されていません。かっこは各 SELECT ステートメントの中で使用できます。
たとえば、次のステートメントで、"IN" の後のかっこと最後のかっこは許可されません。
SELECT c1 FROM t5 WHERE c1 IN ((SELECT c1 FROM t1 UNION SELECT c1 FROM t2) UNION ALL (SELECT c1 FROM t3 UNION SELECT c1 from t4))
テーブル サブクエリ
テーブル サブクエリを使用すると、複数のクエリを組み合わせて 1 つの詳細なクエリにすることができます。テーブル サブクエリは、データベースに残らない動的ビューです。一番上の SELECT クエリが完了したら、テーブル サブクエリに関連付けられたすべてのリソースが解放されます。
メモ: テーブル サブクエリでは、非相関サブクエリのみが使用できます。相関サブクエリは使用できません。
次の改ページ調整の例(1 ページあたり 100 行ずつの 1500 行)は、ORDER BY 句を使用したテーブル サブクエリの使用方法を示しています。
最初の 100 行
SELECT * FROM ( SELECT TOP 100 * FROM ( SELECT TOP 100 * FROM person ORDER BY last_name asc ) AS foo ORDER BY last_name desc ) AS bar ORDER BY last_name ASC
2 番目の 100 行
SELECT * FROM ( SELECT TOP 100 * FROM ( SELECT TOP 200 * FROM person ORDER BY last_name asc ) AS foo ORDER BY last_name DESC ) AS bar ORDER BY last_name ASC
...
15 番目の 100 行
SELECT * FROM ( SELECT TOP 100 * FROM ( SELECT TOP 1500 * FROM person ORDER BY last_name ASC ) AS foo ORDER BY last_name DESC ) AS bar ORDER BY last_name ASC
テーブル ヒント
テーブル ヒント機能を使用すると、クエリの最適化のために、どのインデックスを使用するかを指定することができます。テーブル ヒントは、データベース エンジンが使用するデフォルトのクエリ オプティマイザーより優先されます。
テーブル ヒントで INDEX(0) が指定されていると、エンジンは関連するテーブルのテーブル スキャンを実行します。テーブル スキャンは、インデックスを使用して特定のデータ要素を見つけるのではなく、テーブル内の各行を読み取ります。
テーブル ヒントに INDEX(インデックス名) が指定されている場合、エンジンは インデックス名 を使用し、JOIN 条件の制約や、DISTINCT、GROUP BY、ORDER BY の使用に基づいてテーブルを最適化します。指定されたインデックスでテーブルが最適化できない場合、エンジンは既存のインデックスに基づいて最適化を試みます。
複数のインデックス名を指定した場合、エンジンは最適なパフォーマンスを得られるインデックスを選択するか、OR 最適化のために複数のインデックスを使用します。わかりやすくするために例を示します。以下を想定します。
CREATE INDEX ndx1 on t1(c1)
CREATE INDEX ndx2 on t1(c2)
CREATE INDEX ndx3 on t1(c3)
SELECT * FROM t1 WITH (INDEX (ndx1, ndx2))
WHERE c1 = 1 AND c2 > 1 AND c3 = 1
データベース エンジンは、ndx2 を使用するのではなく ndx1 を使用して、c1 = 1 を最適化します。ndx3 は、テーブル ヒントに含まれていないため、考慮に入れません。
以下について考えてみましょう。
SELECT * FROM t1 WITH (INDEX (ndx1, ndx2))
WHERE (c1 = 1 OR c2 > 1) AND c3 = 1
エンジンは ndx1 と ndx2 の両方を使用して(c1 = 1 OR c2 > 1)を最適化します。
テーブル ヒントの中で複数のインデックス名が表れる順序は重要ではありません。データベース エンジンは、指定されたインデックスから最も優れた最適化を行えるインデックスを選択します。
テーブル ヒント内で重複するインデックス名は無視されます。
結合されたビューでは、FROM 句の最後ではなく、適切なテーブル名の後にテーブル ヒントを指定します。たとえば、次は正しいステートメントです。
SELECT * FROM person WITH (INDEX(Names)), student
WHERE student.id = person.id AND last_name LIKE 'S%'
これに対し、次のステートメントは正しくありません。
SELECT * FROM person, student WITH (INDEX(Names))
WHERE student.id = person.id AND last_name LIKE 'S%'
メモ: テーブル ヒント機能は上級ユーザー向けです。一般的に、データベース クエリ オプティマイザーが最も優れた最適化方法を選択するので、テーブルヒントは必要ではありません。
制限事項
•テーブル ヒントで使用できるインデックス名の最大数は、SQL ステートメントの最大長(64 KB)のみに制限されます。
•テーブル ヒント内のインデックス名は、テーブル名で完全に修飾されていてはなりません。
不正な SQL: | SELECT * FROM t1 WITH (INDEX(t1.ndx1)) WHERE t1.c1 = 1 |
戻り値: | SQL_ERROR |
szSqlState: | 37000 |
メッセージ: | 構文エラー: SELECT * FROM t1 WITH (INDEX(t1.<< ??? >>ndx1)) WHERE t1.c1 = 1 |
•テーブル ヒントは、SELECT ステートメント内でビューと共に使用された場合は無視されます。
不正な SQL: | SELECT * FROM myt1view WITH (INDEX(ndx1)) |
戻り値: | SQL_SUCCESS_WITH_INFO |
szSqlState: | 01000 |
メッセージ: | ビューと共に指定されたインデックス ヒントは無視されます。 |
•インデックス名以外ではゼロが唯一の有効なヒントです。
不正な SQL: | SELECT * FROM t1 WITH (INDEX(85)) |
戻り値: | SQL_ERROR |
szSqlState: | S1000 |
メッセージ: | インデックス ヒントが不正です。 |
•テーブル ヒント内のインデックス名には既存のインデックスを指定する必要があります。
不正な SQL: | SELECT * FROM t1 WITH (INDEX(ndx4)) |
戻り値: | SQL_ERROR |
szSqlState: | S0012 |
メッセージ: | インデックス名が不正です。インデックスが見つかりません。 |
•テーブル ヒントは、サブクエリ AS テーブルには指定できません。
不正な SQL: | SELECT * FROM (SELECT c1, c2 FROM t1 WHERE c1 = 1) AS a WITH (INDEX(ndx2)) WHERE a.c2 = 10 |
戻り値: | SQL_ERROR |
szSqlState: | 37000 |
メッセージ: | 構文エラー:SELECT * FROM (SELECT c1, c2 FROM t1 WHERE c1 = 1) AS a WITH<< ???>>(INDEX(ndx2)) WHERE a.c2 = 10 |
例
この単純な SELECT ステートメントは、Faculty テーブルの全データを取り出します。
SELECT * FROM Faculty
このステートメントによって、person および faculty テーブルから、person テーブル内の id 列と faculty テーブル内の id 列が同じデータが取り出されます。
SELECT Person.id, Faculty.salary FROM Person, Faculty
WHERE Person.id = Faculty.id
============
次の例では、amount_paid の総額が 100 以上の場合に、student_id と amount_paid の総額が billing テーブルから取り出されます。次に、student_id 別にレコードが分類されます。
SELECT Student_ID, SUM(Amount_Paid)
FROM Billing
GROUP BY Student_ID
HAVING SUM(Amount_Paid) >=100.00
式が正の整数リテラルの場合、そのリテラルが結果セット内の列の番号として解釈され、その列について順序付けが行われます。セット関数またはセット関数を含む式については、順序付けは許可されません。
============
FOR UPDATE
次の例ではテーブル t1 を使用して FOR UPDATE の使用法を示します。t1 は DEMODATA サンプル データベースの一部であるとします。ストアド プロシージャは SELECT FOR UPDATE ステートメントのためのカーソルを作成します。ループで t1 から c1=2 の行の各レコードをフェッチし、c1 の値に 4 を設定します。
プロシージャは、IN パラメーターに値 "2" を渡して呼び出します。
この例は、2 人のユーザー A、B が DEMODATA にログインしているものとします。ユーザー A が以下の処理を行います。
DROP TABLE t1
CREATE TABLE t1 (c1 INTEGER, c2 INTEGER)
INSERT INTO t1 VALUES (1,1)
INSERT INTO t1 VALUES (2.1)
INSERT INTO t1 VALUES (1,1)
INSERT INTO t1 VALUES (2.1)
CREATE PROCEDURE p1 (IN :a INTEGER)
AS
BEGIN
DECLARE :b INTEGER;
DECLARE :i INTEGER;
DECLARE c1Bulk CURSOR FOR SELECT * FROM t1 WHERE c1 = :a
FOR UPDATE;
START TRANSACTION;
OPEN c1Bulk;
BulkLinesLoop:
LOOP
FETCH NEXT FROM c1Bulk INTO :i;
IF SQLSTATE = '02000' THEN
LEAVE BulkLinesLoop;
END IF;
UPDATE SET c1 = 4 WHERE CURRENT OF c1Bulk;
END LOOP;
CLOSE c1Bulk;
SET :b = 0;
WHILE (:b < 100000) DO
BEGIN
SET :b = :b + 1;
END;
END WHILE;
COMMIT WORK;
END;
CALL p1(2)
WHILE ループがトランザクションの COMMIT を遅延させることに注意してください。この遅延の間、ユーザー B は、SQLExecDirect "UPDATE t1 SET c1=3 WHERE c1=2" 呼び出しを使用して t1 の更新を試みるとします。これらの行はユーザー A が SELECT FOR UPDATE ステートメントでロックしているため、ユーザー B にはステータス コード 84 が返されます。
============
次の例ではテーブル t1 を使用して、SELECT FOR UPDATE がストアド プロシージャの外部で使用された場合のレコードのロック方法を示します。t1 は DEMODATA サンプル データベースの一部であるとします。
この例は、2 人のユーザー A、B が DEMODATA にログインしているものとします。ユーザー A が以下の処理を行います。
DROP TABLE t1
CREATE TABLE t1 (c1 INTEGER, c2 INTEGER)
INSERT INTO t1 VALUES (1,1)
INSERT INTO t1 VALUES (2.1)
INSERT INTO t1 VALUES (1,1)
INSERT INTO t1 VALUES (2.1)
オプション SQL_AUTOCOMMIT、属性 SQL_AUTOCOMMIT_OFF を使用して SQLSetConnectAttr を呼び出します。
SQLExecDirect "SELECT * FROM t1 WHERE c1 = 2 FOR UPDATE" を呼び出します。
c1 = 2 である 2 つのレコードは、ユーザー A が COMMIT WORK または ROLLBACK WORK ステートメントを発行するまでロックされます。
ユーザー B は、SQLExecDirect "UPDATE t1 SET c1=3 WHERE c1=2" 呼び出しを使用して t1 の更新を試みます。これらの行はユーザー A が SELECT FOR UPDATE ステートメントでロックしているため、ユーザー B にはステータス コード 84 が返されます。
ここで、ユーザー A がオプション SQL_COMMIT を使用して call SQLEndTran を発行したとします。c1 = 2 である 2 つのレコードのロックは解除されます。
これで、ユーザー B は call SQLExecDirect "UPDATE t1 SET c1=3 WHERE c1=2" を発行して c1 の値を変更できます。
============
概算数値リテラル
SELECT * FROM results WHERE quotient =-4.5E-2
INSERT INTO results (quotient) VALUES (+5E7)
============
BETWEEN 述語
式1 BETWEEN 式2 and 式3 という構文では、式1 >= 式2 かつ、式1 <= 式3 の場合に True が返されます。式1 >= 式3 または式1 <= 式2 の場合は、False が返されます。
式2 と式3 は動的パラメーター(たとえば、SELECT * FROM emp WHERE emp_id BETWEEN ?AND ?) にすることができます。
次の例では、ID が 10000 と 20000 の間にある名が person テーブルから取り出されます。
SELECT First_name FROM Person WHERE ID BETWEEN 10000 AND 20000
============
相関名
テーブルと列の相関名はどちらもサポートされています。
次の例では、person テーブルと faculty テーブルからデータが選択されます。2 つのテーブルを区別するためにエイリアスの T1 と T2 を使用しています。
SELECT * FROM Person t1, Faculty t2 WHERE t1.id = t2.id
また、テーブルの相関名は、次の例のように FROM 句を使って指定することもできます。
SELECT a.Name, b.Capacity FROM Class a, Room b
WHERE a.Room_Number = b.Number
============
正確な数値リテラル
SELECT car_num, price FROM cars
WHERE car_num = 49042 AND price = 49999.99
============
IN 述語
これにより、名が Bill と Roosevelt のレコードがテーブル Person から選択されます。
SELECT * FROM Person WHERE First_name IN ('Roosevelt', 'Bill')
============
セット関数
次の例では、Faculty テーブルから最低給与が選択されます。
SELECT MIN(salary) FROM Faculty
MIN(式)、MAX(式)、SUM(式)、STDEV(式)、AVG(式)、COUNT(*)、および COUNT(式)がサポートされています。
COUNT(式)によって、述部にある式の非ヌル値すべてがカウントされます。COUNT(*) ではヌル値を含むすべての値がカウントされます。
次の例では、q 内で a+b がヌルにならないすべての行がカウントされます。
SELECT COUNT(a+b) FROM q
STDEV 関数は、データのサンプルに基づいて、すべてのデータの標準偏差を返します。式は数値データ型である必要があり、8 バイトの DOUBLE が返されます。式の最小値と最大値の差が範囲外である場合は、"浮動小数点のオーバーフローです" エラーになります。式に集計関数を含むことはできません。式フィールドに値が入っている行が少なくとも 2 つはある必要があります。そうでないと、STDEV は計算されず、NULL が返されます。
次の例は、Student サンプル テーブルの成績評価点平均(GPA)フィールドの標準偏差を返します。
SELECT STDEV(Cumulative_GPA) FROM student
============
日付リテラル
日付定数は、SQL ステートメント内に文字列として表記するか、ベンダー文字列に埋め込むことができます。SQL_CHAR およびベンダー文字列表記は、SQL_DATE 型の値として扱われます。これは変換時に重要になります。
Pervasive PSQL では、この関数で概説しているように、拡張 SQL 文法を一部サポートしています。
次の 2 つのステートメントによって、開始日が 1995 年 6 月 5 日より後のすべての授業が返されます。
SELECT * FROM Class WHERE Start_Date > '1995-06-05'
SELECT * FROM Class WHERE Start_Date > {d '1995-06-05'}
Pervasive PSQL では、'YYYY-MM-DD' という日付リテラル書式をサポートしています。
日付の年は 0 ~ 9999 の範囲が可能です。
============
時刻リテラル
次の 2 つのステートメントによって、class テーブルから、授業の開始時刻が 14:00:00 のレコードが取り出されます。
SELECT * FROM Class WHERE Start_time = '14:00:00'
SELECT * FROM Class WHERE Start_time = {t '14:00:00'}
時刻定数は、SQL ステートメント内に文字列として表記するか、ベンダー文字列に埋め込むことができます。文字列表記は SQL_CHAR 型の文字列として、ベンダー文字列表記は SQL_TIME 型の値として扱われます。
Pervasive PSQL では、この関数で概説しているように、拡張 SQL 文法を一部サポートしています。
============
タイムスタンプ リテラル
タイムスタンプ定数は、SQL ステートメント内に文字列として表記するか、ベンダー文字列に埋め込むことができます。Pervasive PSQL では、文字列表記は SQL_CHAR 型の文字列として、ベンダー文字列表記は SQL_TIMESTAMP 型の値として扱われます。Pervasive PSQL では、この関数で概説しているように、拡張 SQL 文法を一部サポートしています。
次の 2 つのステートメントによって、Billing テーブルから、ログの開始日時が 1996-03-28 の 17:40:49 のレコードが取り出されます。
SELECT * FROM Billing WHERE log = '1996-03-28 17:40:49.0000000'
SELECT * FROM Billing WHERE log = {ts '1996-03-28 17:40:49.0000000'}
Pervasive PSQL では、'YYYY-MM-DD HH:MM:SS.MMMMMMM' という時刻リテラル書式をサポートしています。
文字列リテラル
リテラル文字列は、一重引用符で囲んだ文字列で表されます。文字列自体が一重引用符またはアポストロフィを含んでいる場合は、その文字の前にもう 1 つ一重引用符を付ける必要があります。
SELECT * FROM t1 WHERE c1 = 'Roberta''s Restaurant'
SELECT STREET FROM address WHERE city LIKE 'San%'
============
日付演算
SELECT * FROM person P, Class C WHERE p.Date_Of_Birth <
'1973-09-05' and c.Start_date > {d '1995-05-08'} + 30
Pervasive PSQL では、加算または減算する日数が整数で、日付がベンダー文字列に埋め込まれている場合、その整数を日付に加算したり日付から減算したりできます(これは、日付について変換を実行するのと同じです)。
また、ある日付を別の日付から減算して日数を計算することもできます。
============
IF
IF システム スカラー関数によって、条件の真の値に基づく条件付き実行が提供されます。
次の式は、列ヘッダー "Prime1" を出力し、amount_owed 列の値が 2000 の場合は 2000 を、2000 でない場合は 0 を出力します。
SELECT Student_ID, Amount_Owed,
IF (Amount_Owed = 2000, Amount_Owed, Convert(0, SQL_DECIMAL)) "Prime1"
FROM Billing
次の例では、Class テーブルから、Section 列が 001 の場合はその値を、001 でない場合は "xxx" を、列ヘッダー Prime1 の下に出力します。
さらに、列ヘッダー Prime2 の下に、Section 列の値が 002 の場合はその値を、002 でない場合は "yyy" を出力します。
SELECT ID, Name, Section,
IF (Section = '001', Section, 'xxx') "Prime1",
IF (Section = '002', Section, 'yyy') "Prime2"
FROM Class
ネストした IF 関数を使用して、ヘッダー Prime1 とヘッダー Prime2 を合体させることができます。次のクエリは、列ヘッダー Prime の下に、Section 列の値が 001 か 002 の場合は Section 列の値を出力し、それ以外の場合は "xxx" を出力します。
SELECT ID, Name, Section,
IF (Section = '001', Section, IF(Section = '002', Section, 'xxx')) Prime
FROM Class
============
マルチデータベースの結合
必要であれば、データベース名を FROM 句内のエイリアス付きのテーブル名の前に付加して、結合で使用する 2 つ以上の異なるデータベースにあるテーブルを区別することができます。
指定したデータベースはすべて同じデータベース エンジンで処理し、同じデータベース コード ページ設定である必要があります。これらのデータベースは同じ物理ボリューム上になくてもかまいません。現行データベースはセキュリティで保護されていてもいなくてもかまいませんが、結合内のそれ以外のデータベースはセキュリティで保護されていない必要があります。参照整合性に関しては、すべての RI キーが同一のデータベース内に存在している必要があります(
エンコードも参照してください)。
リテラル データベース名は選択リストまたは WHERE 句内で使用することはできません。選択リストまたは WHERE 句内で特定の列を参照する場合は、指定する各テーブルのエイリアスを使用する必要があります。例を参照してください。
2 つの異なるデータベース "accounting" と "customers" が同じサーバー上に存在していると仮定します。次の例のようなテーブル エイリアスと SQL 構文を使って 2 つのデータベースにあるテーブルを結合することができます。
SELECT ord.account, inf.account, ord.balance, inf.address
FROM accounting.orders ord, customers.info inf
WHERE ord.account = inf.account
============
次の例では、2 つのデータベースは "acctdb" と "loandb" です。テーブル エイリアスはそれぞれ "a" と "b" です。
SELECT a.loan_number_a, b.account_no, a.current_bal, b.balance
FROM acctdb.ds500_acct_master b
LEFT OUTER JOIN loandb.ml502_loan_master a
ON (a.loan_number_a = b.loan_number)
WHERE a.current_bal <> (b.balance * -1)
ORDER BY a.loan_number_a
============
左外部結合
次の例は、DEMODATA データベースの "Person" と "Student" テーブルにアクセスして、学生の姓と、名の頭文字、および GPA を取得する方法を示します。LEFT OUTER JOIN を使用すると、"Person" テーブル内のすべての行がフェッチされます(LEFT OUTER JOIN の左側にあるテーブル)。すべての人が GPA を持っているわけではないため、列によっては結果にヌル値を持ちます。以下は、外部結合がどのように働き、両方のテーブルから一致しない行を返すかを示します。
SELECT Last_Name, Left(First_Name,1) AS First_Initial, Cumulative_GPA AS GPA FROM "Person"
LEFT OUTER JOIN "Student" ON Person.ID=Student.ID
ORDER BY Cumulative_GPA DESC, Last_Name
完全に整数の GPA を持つ人全員がわかり、彼らをその姓の長さに従って並べたいとします。MOD ステートメントと LENGTH スカラー関数を使用して、クエリに次の文を追加することにより、これを実現できます。
WHERE MOD(Cumulative_GPA,1)=0 ORDER BY LENGTH(Last_Name)
============
右外部結合
LEFT OUTER JOIN と RIGHT OUTER JOIN との違いは、一致しないすべての行を表示する対象が RIGHT OUTER JOIN の右側に定義されたテーブルである点です。クエリの LEFT OUTER JOIN の部分を RIGHT OUTER JOIN を使用するように変更します。GPA がない場合でも、右テーブル(この場合は "Student")から不一致行がすべて表示される点が異なります。ただし、"Student" テーブル内の行はすべて GPA を持つため、すべての行がフェッチされます。
SELECT Last_Name, Left(First_Name,1) AS First_Initial, Cumulative_GPA AS GPA FROM "Person"
RIGHT OUTER JOIN "Student" ON Person.ID=Student.ID
ORDER BY Cumulative_GPA DESC, Last_Name
============
カルテシアン結合
カルテシアン結合は、両方のテーブルの行を可能な限りすべて組み合わせた行列です。カルテシアン内の行数は、1 番目のテーブル内の行数に 2 番目のテーブル内の行数を掛けた値に等しくなります。
データベース内に次のようなテーブルがあるとします。
表 46 Addr テーブル
EmpID | Street |
E1 | 101 Mem Lane |
E2 | 14 Young St. |
表 47 Loc テーブル
LocID | Name |
L1 | PlanetX |
L2 | PlanetY |
次のステートメントにより、上記のテーブルのカルテシアン結合を実行します。
SELECT * FROM Addr,Loc
次のような結果になります。
表 48 カルテシアン結合を使った SELECT ステートメント
EmpID | Street | LocID | Name |
E1 | 101 Mem Lane | L1 | PlanetX |
E1 | 101 Mem Lane | L2 | PlanetY |
E2 | 14 Young St | L1 | PlanetX |
E2 | 14 Young St | L2 | PlanetY |
============
DISTINCT
DISTINCT を SUM、AVG、COUNT、MIN、および MAX と共に使用することができます(ただし、MIN と MAX の結果は変わりません)。DISTINCT は、総計、平均、件数を求める前に、重複する値を取り除きます。
学部ごとの給与の最低額、最高額、平均額を知りたいと仮定します。このとき、同額の給与は除くことにします。次のステートメントは、computer science 学部以外の学部に対してこれを実行します。
SELECT dept_name, MIN(salary), MAX(salary), AVG(DISTINCT salary) FROM faculty WHERE dept_name<>'computer science' GROUP BY dept_name
同額の給与も含む場合は、次のようにします。
SELECT dept_name, MIN(salary), MAX(salary), AVG(salary) FROM faculty WHERE dept_name<>'computer science' GROUP BY dept_name
============
TOP
SELECT ステートメント内で TOP キーワードを使用し、返される最大行数の値を指定することによって、1 つのステートメントで返される行数を制限することができます。
指定した行数は正のリテラル整数でなければなりません。32 ビットの符号なし整数として定義します。
SELECT ステートメントには、TOP 句と ORDER BY 句の両方を含めることができます。その場合、データベース エンジンはテンポラリ テーブルを生成し、ORDER BY で使用できるインデックスがない場合は、そこにクエリの結果セット全体を置きます。テンポラリ テーブル内の行は ORDER BY 句で指定した順序で並べられ、その順序付けされた結果セットから最初の n 行が返されます。
TOP 句を含むビューは、ほかのテーブルやビューと結合できます。
TOP と
SET ROWCOUNT の主な違いは、SET ROWCOUNT が現在のデータベース セッション中に発行される後続のステートメントすべてに作用するのに対し、TOP は現在のステートメントにのみ作用する点です。
SET ROWCOUNT と TOP の両方をクエリに適用した場合、2 つの値のうち小さい方の値に等しい行数を返します。
============
カーソルのタイプと TOP
TOP 句を用いる SELECT クエリをカーソル内で使用すると、いくつかの状況下で暗黙的にカーソルのタイプが変更されます。下記の表を使用する場合、インデックス付けされていない列に対して ORDER BY を使用する SELECT クエリではテンポラリ テーブルが必要になることを覚えておいてください。インデックス付けされた列に対して ORDER BY を使用する場合、テンポラリ テーブルは必要ありません。
表 49 TOP 句がカーソル タイプに与える影響
元のカーソル タイプ | SELECT クエリでテンポラリ テーブルが必要な場合に変換されるタイプ | SELECT クエリでテンポラリ テーブルが必要ない場合に変換されるタイプ |
動的 | 前方のみ | 静的 |
静的 | 前方のみ | 変更しません |
前方のみ | 変更しません | 変更しません |
SELECT TOP 10 * FROM person -- 10 行を返します
SET ROWCOUNT = 5;
SELECT TOP 10 * FROM person; -- 5 行を返します
SET ROWCOUNT = 12;
SELECT TOP 10 * FROM person ORDER BY id;
-- id 列で順序付けされた全リストから最初の 10 行を返します
============
次の例では、TOP が VIEW、UNION またはサブクエリで使用された場合のさまざまな動作を示します。
CREATE VIEW v1 (c1) AS SELECT TOP 10 id FROM person;
CREATE VIEW v2 (d1) AS SELECT TOP 5 c1 FROM v1;
SELECT * FROM v2 -- 5 行を返します
SELECT TOP 10 * FROM v2 -- 5 行を返します
SELECT TOP 0 * FROM v2 -- 0 行を返します
SELECT TOP 2 * FROM v2 -- 2 行を返します
SELECT TOP 10 id FROM person UNION SELECT TOP 13 faculty_id FROM class -- 14 行を返します
SELECT TOP 10 id FROM person UNION ALL SELECT TOP 13 faculty_id FROM class -- 23 行を返します
SELECT id FROM person WHERE id IN (SELECT TOP 10 faculty_id from class) -- 4 行を返します
SELECT id FROM person WHERE id >= any (SELECT TOP 10 faculty_id from class) -- 1493 行を返します
次の例では、ID が 714662900 より大きいすべての学生について、その姓と支払う義務のある金額を示します。
SELECT p_last_name, b_owed FROM
(SELECT TOP 10 id, last_name FROM person ORDER BY id DESC)
p (p_id, p_last_name),
(SELECT TOP 10 student_id, SUM (amount_owed) FROM billing
GROUP BY student_id ORDER BY student_id DESC)
b (b_id, b_owed)
WHERE p.p_id = b.b_id AND p.p_id > 714662900
ORDER BY p_last_name ASC
不正な例
次の SELECT ステートメントはエラー メッセージを生成します。これは、定義されたビューに TOP 句が含まれているため、結合に参加できないからです。
CREATE VIEW v1 (c1) AS SELECT TOP 10 id FROM person
SELECT * FROM v1 INNER JOIN person ON v1.c1 = person.id
-- エラー メッセージを返します
SELECT * FROM person V v1 ON person.c1 = v1.id
-- エラー メッセージを返します
SELECT * FROM person, v1
-- エラー メッセージを返します
============
テーブル ヒント
このテーブル ヒントの例では、テーブル t1、t2 のいずれかまたは両方を使用します。以下の SQL を使用してサンプルのテーブルを作成し、データを入れることができます。
DROP TABLE t1
CREATE TABLE t1 (c1 INTEGER, c2 INTEGER)
INSERT INTO t1 VALUES (1.10)
INSERT INTO t1 VALUES (1.10)
INSERT INTO t1 VALUES (2.20)
INSERT INTO t1 VALUES (2.20)
INSERT INTO t1 VALUES (3.30)
INSERT INTO t1 VALUES (3.30)
CREATE INDEX it1c1 ON t1 (c1)
CREATE INDEX it1c1c2 ON t1 (c1, c2)
CREATE INDEX it1c2 ON t1 (c2)
CREATE INDEX it1c2c1 ON t1 (c2, c1)
DROP TABLE t2
CREATE TABLE t2 (c1 INTEGER, c2 INTEGER)
INSERT INTO t2 VALUES (1.10)
INSERT INTO t2 VALUES (1.10)
INSERT INTO t2 VALUES (2.20)
INSERT INTO t2 VALUES (2.20)
INSERT INTO t2 VALUES (3.30)
INSERT INTO t2 VALUES (3.30)
テーブル ヒントの使用には、一定の制約が適用されます。
制限事項の SQL 例を参照してください。
============
次の例は、インデックス it1c1c2 で最適化します。
SELECT * FROM t1 WITH (INDEX(it1c1c2)) WHERE c1 = 1
制約が "c1 = 1" のみであるので、これを、インデックス it1c2 ではなく it1c1 で最適化する次の例と対比してみます。
SELECT * FROM t1 WITH (INDEX(it1c2)) WHERE c1 = 1
============
次の例はテーブル t1 のテーブル スキャンを実行します。
SELECT * FROM t1 WITH (INDEX(0)) WHERE c1 = 1
============
次の例は、インデックス it1c1c2 および it1c2c1 で最適化します。
SELECT * FROM t1 WITH (INDEX(it1c1c2, it1c2c1))
WHERE c1 = 1 OR c2 = 10
============
次の例は、ビューの作成でテーブル ヒントを使用します。すべてのレコードがビューから選択されると、SELECT ステートメントはインデックス it1c1c2 で最適化します。
DROP VIEW v2
CREATE VIEW v2 as SELECT * FROM t1 WITH (INDEX(it1c1c2))
WHERE c1 = 1
SELECT * FROM v2
============
次の例はサブクエリでテーブル ヒントを使用し、インデックス it1c1c2 で最適化します。
SELECT * FROM (SELECT c1, c2 FROM t1 WITH (INDEX(it1c1c2))
WHERE c1 = 1) AS a WHERE a.c2 = 10
============
次の例はサブクエリでテーブル ヒントおよび "a" という名前のエイリアスを使用します。このエイリアス名は必要です。
SELECT * FROM (SELECT Last_Name FROM Person AS P
with (Index(Names))) a
============
次の例は、c1 = 1 制約に基づいてクエリを最適化し、インデックス it1c1c2 に基づいて GROUP BY 句を最適化します。
SELECT c1, c2, count(*) FROM t1 WHERE c1 = 1 GROUP BY c1, c2
============
次の例はインデックス it1c1 で最適化し、前の例とは異なり、制約のみで最適化して GROUP BY 句では最適化しません。
SELECT c1, c2, count(*) FROM t1 WITH (INDEX(it1c1))
WHERE c1 = 1 GROUP BY c1, c2
GROUP BY 句は指定したインデックス it1c1 を使用して最適化できないため、データベース エンジンは GROUP BY を処理するのにテンポラリ テーブルを使用します。
============
次の例は JOIN 句でテーブル ヒントを使用し、インデックス it1c1c2 で最適化します。
SELECT * FROM t2 INNER JOIN t1 WITH (INDEX(it1c1c2))
ON t1.c1 = t2.c1
これを、テーブル ヒントを使用せずインデックス it1c1 で最適化する次のステートメントと対比してみます。
SELECT * FROM t2 INNER JOIN t1 ON t1.c1 = t2.c1
============
次の例は JOIN 句でテーブル ヒントを使用し、テーブル t1 でテーブル スキャンを実行します。
SELECT * FROM t2 INNER JOIN t1 WITH (INDEX(0)) ON t1.c1 = t2.c1
これを、同じくテーブル t1 のテーブル スキャンを実行する次の例と対比してみます。ただし、JOIN 句が使用されていないため、このステートメントはテンポラリ テーブル結合を使用します。
SELECT * FROM t2, t1 WITH (INDEX(0)) WHERE t1.c1 = t2.c1
関連項目