アップデート
オラクルの場合:
FROM mytable t
JOIN ( SELECT ADD_MONTHS(TRUNC(SYSDATE,'Q'),3) AS b
, ADD_MONTHS(TRUNC(SYSDATE,'Q'),-3) AS e
FROM DUAL
) dr
ON NOT ( t.effective_date_from >= dr.e OR t.effective_date_to < dr.b )
OR ( t.effective_date_from IS NULL AND t.effective_date_to IS NULL )
MySQL の場合:
FROM mytable t
JOIN ( SELECT MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-2 QUARTER AS b
, MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-0 QUARTER AS e
) dr
ON NOT ( t.effective_date_from >= dr.e OR t.effective_date_to < dr.b )
OR ( t.effective_date_from IS NULL AND t.effective_date_to IS NULL )
slOppy からの回答を確認し、質問を再度確認した後、2 つの日付列と がeffective_date_from
あり、と日付の値の間の任意の時点にあるeffective_date_to
行をおそらく取得したいと考えていることを考慮していないことに気付きました。指定された日付範囲内の任意の時刻 (前四半期の初めから次の四半期の初めまで)。from
to
簡単にするために (今のところ)、発効日がfrom < to
.
drb
考えられるケースは、(大雑把に) 次のように表すことができdre
ます。 ~の間の発効日effective_date_from
edf
effective_date_to
edt
edf
edt
drb dre
<---> | | case 1: edt < drb
<---|----> | case 2: drb between edf and edt
<--|-------|----> case 3: edf < drb AND edt > dre
| <---> | case 4: edf > drb AND edt < dre
| <--|---> case 5: edf between drb and dre AND edt > dre
| | <---> case 6: edf > dre
| |
<---> | case e1: edt = drb
<--|-------> case e2: edf > drb AND edt = dre
<---> | case e3: edf = drb and edt < dre
<-------> case e4: edf = drb and edt = dre
<-------|--> case e5: edf = drb and edt > dre
| <---> case e6: edf > drb AND edt = dre
| <---> case e7: edf = dre
ケース 2 から 5 およびエッジ ケース e1 から e6 を満たす行を返すように求めていると思います。これは、ケース 1、6、および e7 を除くすべてのケースです。
ケース 1 とケース 6 をテストし、それを否定する述語を書くことができれば、あなたの望む結果が得られるはずです。このようなもの:
時間コンポーネントを考慮して日時を処理するには:
WHERE NOT ( effective_date_to < drb OR effective_date_from >= dre )
(生成する式drb
とdre
(日付範囲の開始と日付範囲の終了)は、元の回答に示されています。)
effective_date_from
との両方が NULL である行も返すにeffective_date_to
は、そのケースを処理する別の条件を追加できます。
インライン ビューを使用してこれらの式を提供すると、回答の先頭に SQL が表示されます。
私は以前、次のような変わったケースを棚上げしましたeffective_date_from > effective_date_to
。それらの行が有効かどうか、およびそれらが返される条件を把握する必要があります。
元の答え:
これは、 OracleとMySQLの両方で実現できます。私が使用するアプローチは、現在の日付を基準にして、各四半期の「開始日」を最初に生成することです。これらの日付値 (または日付値を返す式) を述語で参照できます。
MySQLで四半期の「開始日」を導出するには、関数を利用できQUARTER()
ます。(この関数は、指定された DATE 値から 1 ~ 4 の整数値を返します。YEAR
および MAKEDATE 関数と組み合わせて、次のように、現在のシステム日付から各四半期の「開始日」を生成できます。
SELECT MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-0 QUARTER AS next_q
, MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-1 QUARTER AS this_q
, MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-2 QUARTER AS prev_q
next_q this_q prev_q
---------- ---------- ------------
2013-10-01 2013-07-01 2013-04-01
これらの日付値を取得したら、それは簡単です。特定の日付列 (mydate
次の例) の値が前四半期または現在の四半期内にある行のみを取得するには、その日付列を上記の 2 つの式と比較するだけです。
WHERE mydate >= MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-2 QUARTER
AND mydate < MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-0 QUARTER
Oracleでは、アプローチは同じです。違いは、相対的な四半期の開始日を導き出す方法にあります。Oracle では、次のような式を使用できます。
-- ALTER SESSION SET nls_date_format = 'YYYY-MM-DD';
SELECT ADD_MONTHS(TRUNC(SYSDATE,'Q'),3) AS next_q
, ADD_MONTHS(TRUNC(SYSDATE,'Q'),0) AS this_q
, ADD_MONTHS(TRUNC(SYSDATE,'Q'),-3) AS prev_q
FROM DUAL
NEXT_Q THIS_Q PREV_Q
---------- ---------- ------------
2013-10-01 2013-07-01 2013-04-01
したがって、 の値がmydate
現在または前の四半期にある行を取得するには、列をこれらの式の 2 つと比較します。
WHERE mydate >= ADD_MONTHS(TRUNC(SYSDATE,'Q'),-3)
AND mydate < ADD_MONTHS(TRUNC(SYSDATE,'Q'),3)
(前の四半期の開始日以降で、次の四半期の開始日未満)。
これらの「開始日」を使用する少し異なる方法は、インライン ビューを使用して日付の値を返すことです。これにより、テストできる別のクエリが得られ、式に列名を割り当てることができます。dr
ここでは、インライン ビューにエイリアス (日付範囲) を使用します。
オラクル
FROM mytable t
JOIN ( SELECT ADD_MONTHS(TRUNC(SYSDATE,'Q'),3) AS bd_next_qtr
, ADD_MONTHS(TRUNC(SYSDATE,'Q'),-3) AS bd_prev_qtr
FROM DUAL
) dr
ON t.mydate >= dr.bd_prev_qtr
AND t.mydate < dr.bd_next_qtr
MySQL
FROM mytable t
JOIN ( SELECT MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-2 QUARTER AS bd_next_qtr
, MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-0 QUARTER AS bd_prev_qtr
) dr
ON t.mydate >= dr.bd_prev_qtr
AND t.mydate < dr.bd_next_qtr