2017-11-14 9 views
0

tbl_emailsテーブル内の未送信の電子メールをすべて選択し、ステータスを「送信済み」に更新する必要があります。私はまずそれらを@tempに選択します。その後、ステータスを更新します。最後に、@ tempを選択します。MySQLエラー1241(21000):更新前に返されたエントリにオペランドが1列含まれている必要があります

CREATE DEFINER = [email protected] PROCEDURE get_unsent_emails() 
     SET @temp = (SELECT * FROM tbl_emails WHERE email_sent = 0); 
     UPDATE tbl_emails 
     SET email_sent = 1 
     WHERE email_sent = 0; 
     SELECT @temp; 

は、私は次のエラーを取得する:

MySQL ERROR 1241 (21000): Operand should contain 1 column(s)

〜ストアドプロシージャ内で一時テーブルを使用していないのはなぜ

+2

@temp変数には、クエリで1つの列のみが含まれている必要があります。 –

答えて

2

CREATE DEFINER = [email protected] PROCEDURE get_unsent_emails() 
     CREATE TEMPORARY TABLE temp AS (SELECT * FROM tbl_emails WHERE email_sent = 0); 
     UPDATE tbl_emails 
     SET email_sent = 1 
     WHERE email_sent = 0; 
     SELECT * FROM temp; 
     DROP TEMPORARY TABLE temp; 

編集のでspencer7593さんのコメントオフ競合状態
を防ぎます。

テーブルのtbl_emailsにidカラムがあり、それがPRIMARY KEYであると仮定します。

CREATE DEFINER = [email protected] PROCEDURE get_unsent_emails() 
     CREATE TEMPORARY TABLE temp AS (SELECT * FROM tbl_emails WHERE email_sent = 0); 
     UPDATE tbl_emails 
     SET email_sent = 1 
     WHERE email_sent = 0 AND id IN(SELECT id FROM temp); 
     SELECT * FROM temp; 
     DROP TEMPORARY TABLE temp; 
+2

このパターンは競合状態の影響を受けます。別のセッションが 'email_sent = 0'の行をこのプロシージャと同時に' tbl_emails'に挿入すると、新しい行はSELECTには見えませんが、UPDATEには見えます。それに従わないパターンは、tempに挿入された 'tbl_emails'の行だけを更新することになります。 (プライマリキーまたは「tbl_emails」のユニークキーを使用したJOIN操作を使用) – spencer7593

+0

@ spencer7593本当に競合状態は考えられませんでしたが、あなたは正しいです。それは競合状態を引き起こす可能性があります。しかし、あなたは 'AND id IN(SELECT id FROM temp)'を使ってJOINを使う必要はありません。 –

+0

+10。 2番目の形式(競合状態を避ける)では、 'email_sent = 0 AND'を省略することができます。私はSELECTを追加することを避け、内部結合を行う** 'UPDATE table_emails t JOIN temp s ON s.pk = t.pk SET t.email_sent = 1' ** – spencer7593

関連する問題