sql >> データベース >  >> RDS >> Mysql

同じテーブル内の2つの日付範囲を比較する

    IBM Informix Dynamic Server 11.50.FC6を使用すると、このSQLシーケンスを使用して、必要な結果を得ることができます。

    セットアップ

    CREATE TABLE sales
    (
        id       INTEGER NOT NULL,
        id_store INTEGER NOT NULL,
        date     DATE NOT NULL,
        total    DECIMAL(10,2) NOT NULL
    );
    
    INSERT INTO sales VALUES( 1, 1, '2010-01-01', 500.00);
    INSERT INTO sales VALUES( 2, 1, '2010-01-02', 185.00);
    INSERT INTO sales VALUES( 3, 1, '2010-01-03', 135.00);
    INSERT INTO sales VALUES( 4, 1, '2009-01-01', 165.00);
    INSERT INTO sales VALUES( 5, 1, '2009-01-02', 175.00);
    INSERT INTO sales VALUES( 6, 5, '2010-01-01', 130.00);
    INSERT INTO sales VALUES( 7, 5, '2010-01-02', 135.00);
    INSERT INTO sales VALUES( 8, 5, '2010-01-03', 130.00);
    INSERT INTO sales VALUES( 9, 6, '2010-01-01', 100.00);
    INSERT INTO sales VALUES(10, 6, '2010-01-02',  12.00);
    INSERT INTO sales VALUES(11, 6, '2010-01-03',  85.00);
    INSERT INTO sales VALUES(12, 6, '2009-01-01', 135.00);
    INSERT INTO sales VALUES(13, 6, '2009-01-02', 400.00);
    INSERT INTO sales VALUES(14, 6, '2009-01-07',  21.00);
    INSERT INTO sales VALUES(15, 6, '2009-01-08',  45.00);
    INSERT INTO sales VALUES(16, 8, '2009-01-09', 123.00);
    INSERT INTO sales VALUES(17, 8, '2009-01-10', 581.00);
    

    クエリ

    SELECT *
      FROM (SELECT s1.id AS s1id,
                   NVL(s1.id_store, s2.id_store) AS s1store,
                   NVL(s1.date, MDY(MONTH(s2.date), DAY(s2.date),
                                    YEAR(s2.date)+1)) AS s1date,
                   s1.total AS s1total,
                   s2.id AS s2id,
                   NVL(s2.id_store, s1.id_store) AS s2store,
                   NVL(s2.date, MDY(MONTH(s1.date), DAY(s1.date),
                                    YEAR(s1.date)-1)) AS s2date,
                   s2.total AS s2total
              FROM sales AS s1 FULL JOIN sales AS s2
                ON s1.id_store = s2.id_store
               AND s1.date BETWEEN '2010-01-01' AND '2010-01-10'
               AND s2.date BETWEEN '2009-01-01' AND '2009-01-10'
               AND DAY(s1.date)   = DAY(s2.date)
               AND MONTH(s1.date) = MONTH(s2.date)
           ) AS s3
     WHERE s1_date BETWEEN '2010-01-01' AND '2010-01-10'
       AND s2_date BETWEEN '2009-01-01' AND '2009-01-10'
     ORDER BY s1_id_store ASC, s1_date ASC;
    

    結果

    s1id s1store  s1date     s1total  s2id s2store  s2date     s2total
     1       1    2010-01-01  500.00   4       1    2009-01-01  165.00
     2       1    2010-01-02  185.00   5       1    2009-01-02  175.00
     3       1    2010-01-03  135.00           1    2009-01-03             
     6       5    2010-01-01  130.00           5    2009-01-01             
     7       5    2010-01-02  135.00           5    2009-01-02             
     8       5    2010-01-03  130.00           5    2009-01-03             
     9       6    2010-01-01  100.00  12       6    2009-01-01  135.00
    10       6    2010-01-02   12.00  13       6    2009-01-02  400.00
    11       6    2010-01-03   85.00           6    2009-01-03             
             6    2010-01-07          14       6    2009-01-07   21.00
             6    2010-01-08          15       6    2009-01-08   45.00
             8    2010-01-09          16       8    2009-01-09  123.00
             8    2010-01-10          17       8    2009-01-10  581.00
    

    説明

    これを「正しく」するためには、かなりの実験が必要でした。 Informixには、月、日、年の3つの整数引数をとるDATEコンストラクター関数MDY()があります(名前はニーモニックです)。また、3つの分析関数、DAY()、MONTH()、およびYEAR()があり、日付引数の日、月、および年を返します。 FULL JOINを使用した内部クエリでは、左側と右側の両方にnullが含まれる結果が得られます。 ON句の5つの部分からなる基準が必要と思われます。それ以外の場合、外部クエリの基準は、より複雑で混乱を招く必要があります。次に、外側の選択の基準により、適切なデータが選択されていることが保証されます。内部クエリのNVL()式の利点の1つは、ストアID列が同じでnullではなく、どちらの日付列もnullでないことです。そのため、ストアIDといずれかの日付列でのorderby句が簡単になります。

    Informixでは、日付式を次のように作り直すこともできます。

    NVL(s1.date, s2.date + 1 UNITS YEAR)
    NVL(s2.date, s1.date - 1 UNITS YEAR)
    

    実際には、その表記法で舞台裏で複数の型変換が行われていますが、同じ結果が得られ、余分な計算はおそらくそれほど重要ではありません。

    Informixでの待機にも問題があります。 2月29日には1年を加算または減算することはできません。これは、翌年または前年に2月29日がないためです。データに注意する必要があります。そうでない場合は、2008-02-29のデータを2009-02-28と比較する(および2008-02-28のデータを2009-02-28と比較する)ことになる可能性があります。 「複式簿記」と呼ばれるプロセスがありますが、これはそれが意味するものではなく、「2008-02-29プラス1年」が2009-02-28の場合、計算が混乱する可能性があります。 Informixはエラーを生成します。それはあまり役に立ちません。おそらく、売上を比較する日付がないため、2008-02-29に1年を加えたNULLを返すようにストアドプロシージャをコーディングする場合があります。

    日付演算をMySQLにかなり簡単に適応させることができるはずです。残りのコードを変更する必要はありません。



    1. Oracleの数値関数かどうかを確認します

    2. 計算列を使用して同じビューで別の列を計算する方法

    3. SQLiteUNIQUE制約

    4. MySQLでアクセントに敏感な主キーを使用する