6

タイムスタンプが自動更新に設定されたテーブル フォリオがあります。

CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

PHP の PDO ステートメントが原因で、タイムスタンプが更新されません。

$statement = $this->connection->prepare("
INSERT INTO folio(publication, productId) 
VALUES(:publication, :productId) 
ON DUPLICATE KEY UPDATE 
id=LAST_INSERT_ID(id), publication=:publication, productId=:productId");

次の手動アプローチは機能しますが、望ましくありません。

$statement = $this->connection->prepare(
"INSERT INTO folio(publication, productId) 
VALUES(:publication, :productId) 
ON DUPLICATE KEY UPDATE 
id=LAST_INSERT_ID(id), publication=:publication, productId=:productId, timestamp=NOW()");

更新:これが私のフォリオテーブル構造です

CREATE TABLE `folio` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `publication` varchar(255) DEFAULT NULL,
  `productId` varchar(255) DEFAULT NULL,
  `timestamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_folio` (`publication`,`productId`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;

更新 2: タイムスタンプを非 null に設定した後のテーブル構造

CREATE TABLE `folio` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `publication` varchar(255) DEFAULT NULL,
  `productId` varchar(255) DEFAULT NULL,
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_folio` (`publication`,`productId`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
4

3 に答える 3

10

私が見る限り、クエリの問題は、timestampフィールドをヌル可能にしたことが原因である可能性があります

`timestamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

NOT NULL にしてみてください - 有効なデフォルト値があるため、MySQL はクエリで値が提供されていないと文句を言うことはありません。

`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

また、timestampフィールドの名前をより適切なものに変更してみてください。

`changed_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

また、私のコメントで述べたように、セクション内のすべてのフィールドを提供する必要はありませんが、ON DUPLICATE KEY データ フィールドのみ を提供する必要があります。

INSERT INTO folio(publication, productId) 
VALUES(:publication, :productId) 
ON DUPLICATE KEY UPDATE 
    publication=:publication, 
    productId=:productId

これは、MySQL が重複キー状態を検出した場合、新しい行を挿入せずに既存の行を更新するため、id列をそのままにしておく必要があるためです。

アップデート

列を更新しないことはtimestamp文書化された動作であるようです - TIMESTAMP列のMySQLマニュアル

必要な段落を引用:

列が自動更新されている場合、行内の他の列の値が現在の値から変更されると、現在のタイムスタンプに自動的に更新されます。他のすべての列が現在の値に設定されている場合、列は変更されません。他の列が変更されたときに列が更新されないようにするには、明示的に現在の値に設定します。他の列が変更されていない場合でも列を更新するには、明示的に値を設定します (たとえば、CURRENT_TIMESTAMP に設定します)。

したがって、すべての条件を満たしています:)-レコードを挿入すると、タイムスタンプが正しく入力されるはずです。しかし、更新するために重複した値を提供するとtimestamp、MySQL は行に既に存在する値が設定されていることを認識し (そうしないと重複しない)、列を更新しませんtimestamp

したがって、解決策は簡単で、すでにあなたが見つけたものですtimestamp。重複した値を指定するたびに、列を明示的に更新します。たとえば、次のようになります。

INSERT INTO folio(publication, productId) 
VALUES(:publication, :productId) 
ON DUPLICATE KEY UPDATE 
    `timestamp` = NOW()

とにかく、timestampNOT NULL を作成しても害はありません。

于 2014-06-09T21:15:55.467 に答える
1

新しい INSERT 値が重複行の古い値と同じである場合、明らかに MySQL は UPDATE を実行しないため、ON UPDATE CURRENT_TIMESTAMP は起動されません。:(

したがって、厄介な回避策として、ダミー フィールドをテーブルに追加して、UPDATE を強制的に発生させることができます (ID が重複している場合)。

$statement = $this->connection->prepare("
    INSERT INTO folio(publication, productId) 
      VALUES(:publication, :productId) 
      ON DUPLICATE KEY UPDATE 
      id=LAST_INSERT_ID(id), publication=:publication, productId=:productId,
      dummy = NOT dummy
");

...ここのユーザーコメントで提案されているように:http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

于 2014-06-09T22:13:02.810 に答える