5

クエリを適切に実行するのに問題があり、INSERTこの特定の問題を解決するものを Google または Stack Overflow で見つけることができないようです。

注目のエントリ用の簡単なテーブルを作成しようとしています。ここでは、entry_id現在の順序とともにテーブルに保存されます。

私の望ましい出力はこれです:

現在、featuredテーブルに次の 3 つのエントリがある場合:

featured_id    entry_id    featured_order
1              27          0
2              54          1
4              23          2

featured_order次のエントリは=3で保存したい。

次のクエリをうまく動作させようとしています:

INSERT INTO `featured`
(
    `entry_id`, `featured_order`
)
VALUES
(
    200,
    (SELECT COUNT(*) AS `the_count` FROM `featured`)
)

私が得ているエラーは次のとおりYou can't specify target table 'featured' for update in FROM clauseです。

エラーを発生させずにカウントを取得するソリューションを手伝ってくれる人はいますか?

前もって感謝します!

4

5 に答える 5

15

ここにクールなものがあります:MySQLのINSERT . . . SELECT

INSERT INTO `featured`
(
    `entry_id`, `featured_order`
)
SELECT 200, COUNT(*) + 1
FROM `featured`

サブクエリは必要ありません。


@Bohemianには良い点があります:

このアプローチを使用する場合は、max(featured_order)+1を使用することをお勧めします

したがって、より適切なクエリはおそらく次のようになります。

INSERT INTO `featured`
(
    `entry_id`, `featured_order`
)
SELECT 200, MAX(`featured_order`) + 1
FROM `featured`

彼の答えに記述されている彼のトリガー方法は、あなたが望むことを達成するための良い方法でもあります。


クエリ1の潜在的な問題は、行を削除するとランクが削除され、に重複が生じることですfeatured_order。2番目のクエリでは、これは問題ではありませんが、自動インクリメント列を使用しているかのように、ギャップが生じます。

絶対にギャップのない注文が必要な場合、私が知っている最善の解決策は、この一連のクエリを実行することです。

SET @pos:=0;

DROP TABLE IF EXISTS temp1;

CREATE TEMPORARY TABLE temp1 LIKE featured;

ALTER TABLE featured ORDER BY featured_order ASC;

INSERT INTO temp1 (featured_id, entry_id, featured_order) 
SELECT featured_id, entry_id, @pos:=@pos+1 FROM words;

UPDATE featured 
JOIN temp1 ON featured.featured_id = temp1.featured_id 
SET featured.rank = temp1.rank;

DROP TABLE temp1;

行を削除するたびに

于 2011-05-27T01:56:31.653 に答える
3

トリガーを使用します。

drop trigger if exists featured_insert_trigger; 

delimiter //
create trigger featured_insert_trigger before insert on featured
for each row
begin
  set new.featured_order = ifnull((select max(featured_order) from featured), -1) + 1;
end; //
delimiter ;

インサートは次のようになります。

insert into featured (entry_id) values (200);

featured_orderFeatured_order の最大値に 1 を加えた値に設定されます。これにより、削除/更新される行に対応し、常に一意性が保証されます。

ifnullテーブルに行がない場合、最初の値はゼロになります。

このコードは正しく動作することがテストされています。

于 2011-05-27T01:57:28.503 に答える
3
INSERT INTO `featured`
(
    `entry_id`, `featured_order`
)
VALUES
(
    200,
    (SELECT COUNT(*) AS `the_count` FROM `featured` F1)
)

修正は、「F1」テーブル エイリアスを追加するだけです。

この標準的な SQL ソリューションは、さまざまな dbms (mysql だけでなく) で正常に動作します。


また、以下の改善を提案します。

  • SELECT COUNT(*) +1 (問題: 一部の行が削除されると、既存のインデックスと衝突する可能性があります)

  • SELECT MAX(featured_order)+1 (問題: 空のテーブルへの最初の挿入でエラーが発生する)

SELECT (COALESCE(MAX(featured_order), 0)+1) (問題なし)

于 2016-10-19T10:27:10.780 に答える
2

問題を解決するエイリアスを簡単に使用する必要があります:

INSERT INTO `featured`
(
    `entry_id`, `featured_order`
)
VALUES
(
    200,
    (SELECT COUNT(*) AS `the_count` FROM `featured` as f1)
)
于 2011-05-27T05:13:01.423 に答える
-1

サブクエリに関するMySQLマニュアルから:

もう1つの制限は、現在、テーブルを変更して、サブクエリで同じテーブルから選択することはできないということです。

おそらく、サブクエリのエイリアスまたは結合(それ以外の場合は役に立たない)がここで役立ちます。

編集:回避策があることがわかりました。回避策については、http://www.xaprb.com/blog/2006/06/23/how-to-select-from-an-update-target-in-mysql/で説明されています。

于 2011-05-27T01:56:38.500 に答える