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

フィールドがnullの場合にのみ一意性制約を設定します

    MySQLはfunctionalをサポートしています重要な部分 8.0.13以降 。

    • バージョンが十分に新しい場合は、インデックスを次のように定義できます。

      UNIQUE(`user_id`, `test_id`, (IFNULL(`completed_date`, -1)))
      

      dbfiddle.ukのデモ

      上記のインデックスは、完了した実行の日付の重複を防ぐことにも注意してください。それらが有効である必要がある場合は、わずかに変更されたインデックスが機能します:

      UNIQUE(`user_id`, `test_id`, (
          CASE WHEN `completed_date` IS NOT NULL
          THEN NULL
          ELSE 0
      END))
      

      dbfiddle.ukのデモ

      それから少し汚れた感じがしますが;)

    • 少なくともバージョン5.7をお持ちの場合 (仮想)生成された列を使用できます 回避策として:

      CREATE TABLE `executed_tests` (
          `id` INTEGER AUTO_INCREMENT NOT NULL,
          `user_id` INTEGER NOT NULL,
          `test_id` INTEGER NOT NULL,
          `start_date` DATE NOT NULL,
          `completed_date` DATE,
          `_helper` CHAR(11) AS (IFNULL(`completed_date`, -1)),
          PRIMARY KEY (`id`),
          UNIQUE(`user_id`, `test_id`, `_helper`)
      );
      

      dbfiddle.ukのデモ

    • 5.6で立ち往生している場合 次に、通常の(非仮想)列とわずかに変更されたINSERTの組み合わせ ステートメントは機能します:

      CREATE TABLE `executed_tests` (
          `id` INTEGER AUTO_INCREMENT NOT NULL,
          `user_id` INTEGER NOT NULL,
          `test_id` INTEGER NOT NULL,
          `start_date` DATE NOT NULL,
          `completed_date` DATE,
          `is_open` BOOLEAN,
          PRIMARY KEY (`id`),
          UNIQUE(`user_id`, `test_id`, `is_open`)
      );
      

      この場合、is_openを設定します trueに 不完全な実行およびNULL 完了後、2つのNULL sは等しくないものとして扱われます。

      dbfiddle.ukのデモ




    1. PostgreSQL:これまでの連続日数を検索

    2. JavaでUUIDをbinary(16)として保存する方法

    3. Eloquent ORM/laravelを使用したプリペアドステートメント

    4. 1対多の関係を維持する場合の制約違反