[〜#〜] sql [〜#〜]に問題があります。
別の行の値が条件に一致する場合にのみ、特定の行の値を更新したい。次に、2行目の別の値を更新します。
この方法で説明するとわかりにくいので、コードを次に示します(mysqliを使用してパラメーターをバインドします)。
--mariaDB:
UPDATE `accountlist` JOIN `data` ON `accountlist`.`id`=`data`.`id`
SET `upvotes`= `upvotes` + (`user`= ?),
`allow` = (CASE WHEN `accountlist`.`id` = ?
THEN ?
ELSE `allow`
END)
WHERE (SELECT `allow` FROM `data` WHERE `id` = ?) < ?;
--mysql:
UPDATE `accountlist` JOIN `data` ON `accountlist`.`id`=`data`.`id`
SET `upvotes`= `upvotes` + (`user`= ?),
`allow` = (CASE WHEN `accountlist`.`id` = ?
THEN ?
ELSE `allow`
END)
WHERE `data`.`id` = ? AND `allow` < ?;
--params sample: "admin", 2, "2020-04-20", 2, "2020-04-20"
-- (same value here means always same value)
ローカルホストとホストに異なるデータベースがあるため、MySQLバージョンと非MySQLバージョンの両方を維持する必要があり、何らかの理由で最初のバージョンがMySQLで機能しません。
data
は、accountlist
と1対1の関係にある別のテーブルです(同じid
sの行数は常に同じです)。
とにかく、すべてを簡略化するために、user=?
row 1である行とaccountlist.id=?
row 2である行を呼び出します。
私がしたいことは:
user
on row 1 update allow
on row 2が?
より小さい場合allow
を更新行2(allow
on 行2が?
より小さい場合)2番目のポイントの状態はそれ自体に更新されるため、それほど重要ではありませんが、それが私がそれを行うことができた唯一の方法です。
私の問題:
upvotes
on row 1を更新しますが、allow
on row 2は変更しません。arrow
on row 2を更新しますが、user
on row 1は変更しません。独自のMySQL +非MySQLバージョンを意味する可能性のあるソリューションはありますか?
更新:
ここに例を示します:
accountlist data
|------------|---------------| |------------|--------------|----------|
| id | user | | id | allow | upvotes |
|------------|---------------| |------------|--------------|----------|
A: | 1 | admin | | 1 | 2020-04-18 | 2 |
B: | 2 | foo | | 2 | 2020-04-20 | 0 |
C: | 3 | bar | | 3 | 2020-04-22 | 1 |
|------------|---------------| |------------|--------------|----------|
params: "admin"、2、 "2020-04-20"、2、 "2020-04-20" allow
on row B is not lower than 2020-04-20
:
パラメータ:「admin」、2、「2020-04-22」、2、「2020-04-22」allow
on row Bは2020-04-20
よりも小さい:
upvotes
on 行A増加(2
-> 3
)allow
on row Bが更新されます(2020-04-20
-> 2020-04-22
)params: "bar"、1、 "2020-04-19"、1、 "2020-04-19" allow
on row A is lower than 2020-04-19
:
upvotes
on row Cが増加しました(1
-> 2
)allow
on row Aが更新されます(2020-04-18
-> 2020-04-19
)更新2:
私がやりたいこと:ser 1が賛成したい場合ser 2(誰でも1日に1回しか他の人を反対票を投じることができます)、ボタンをクリックすると、allowed
(on彼の行)は翌日と比較されます:
allowed
が翌日と等しい場合、それはser 1がすでに誰かに賛成していることを意味します(彼はser 2、ユーザーまたは他の誰か)なので、何も変更されませんallowed
が翌日より小さい場合、それはser 1が誰かを賛成することを許可されていることを意味します。したがって、upvote
on ser 2の行はser 1の行のallow
がインクリメントされ、翌日に更新されます「もしser 1またはser 2が実際に存在しない場合はどうなりますか」、または「もしser 1が試みたら自分自身を賛成しますか?* [〜#〜] php [〜#〜]コードで確認します。
物事を見ていきましょう。まず、各列を修飾して、どの列がどのテーブルにあるかを確認します。
UPDATE a JOIN d ON a.`id` = d.`id`
SET d.`upvotes`= d.`upvotes` + (a.`user`= ?),
d.`allow` = (CASE WHEN a.`id` = ?
THEN ?
ELSE d.`allow`
END)
WHERE d.`id` = ? AND d.`allow` < ?;
ああ、2つのテーブルはid
で1:1です。では、同じテーブルであるとしましょう。 (そして、おそらくそうすべきです。通常、1:1は良いスキーマ設計ではありません。)
UPDATE ad
SET `upvotes`= `upvotes` + (`user`= ?),
`allow` = (CASE WHEN `id` = ?
THEN ?
ELSE `allow`
END)
WHERE `id` = ? AND `allow` < ?;
CASE
が無駄になっていることは明らかです。したがって、クエリは次のように簡素化されます。
UPDATE ad
SET `upvotes`= `upvotes` + (`user`= ?),
`allow` = ?
WHERE `id` = ? AND `allow` < ?;
では、2つのテーブルに戻りましょう。
UPDATE a JOIN d ON a.`id` = d.`id`
SET d.upvotes = d.upvotes + (a.user = ?),
d.allow = ?
WHERE d.id = ? AND d.allow < ?;
それは別の形につながります。 (これが良いかどうかはわかりません。)
UPDATE d
SET d.upvotes = d.upvotes +
( ( SELECT user = ? FROM a WHERE a.id = d.id ) )
d.allow = ?
WHERE d.id = ? AND d.allow < ?;
または、(ここでもおそらく大きな違いはありません):
UPDATE d
SET d.upvotes = d.upvotes +
EXISTS ( SELECT user = ? FROM a WHERE a.id = d.id )
d.allow = ?
WHERE d.id = ? AND d.allow < ?;
私はあなたの問題の解決策を見つけようとしました、そしておそらく私はここで正しいワークフローを理解している答えのIDを持っています:各ユーザーは1日に1回賛成投票できます
その例では、「admin」、2、「2020-04-20」、2、「2020-04-20」
私は正しいですか?はいの場合、ここに私の解決策
mariadb
UPDATE data SET upvotes = CASE WHEN id = (SELECT id FROM accountlist WHERE accountlist.user = ?)
AND
(SELECT allow FROM data inner join accountlist on accountlist.id = data.id
where accountlist.id = ? )< ?
THEN upvotes + 1
ELSE upvotes
END,
allow = CASE WHEN id = ?
THEN ?
ELSE allow
END
mysql
UPDATE data
SET upvotes = CASE WHEN id = (SELECT id FROM (select * from accountlist) as al WHERE al.user = "bar")
AND
(SELECT allow FROM (select * from data) as d inner join (select * from accountlist) as al1 on al1.id = d.id where al1.id = 1)<"2020-04-19"
THEN upvotes + 1
ELSE upvotes
END,
allow = CASE WHEN id = 1
THEN "2020-04-19"
ELSE allow
END;
作成されたデータベース:
accountlist data
|------------|---------------| |------------|--------------|----------|
| id | user | | id | allow | upvotes |
|------------|---------------| |------------|--------------|----------|
A: | 1 | admin | | 1 | 2020-04-18 | 2 |
B: | 2 | foo | | 2 | 2020-04-20 | 0 |
C: | 3 | bar | | 3 | 2020-04-22 | 1 |
|------------|---------------| |------------|--------------|----------|
値:「admin」、「2」、「2020-04-20」、「2」、「2020-04-20」=>変更なし
「admin」、「2」、「2020-04-22」、「2」、「2020-04-22」
accountlist data
|------------|---------------| |------------|--------------|----------|
| id | user | | id | allow | upvotes |
|------------|---------------| |------------|--------------|----------|
A: | 1 | admin | | 1 | 2020-04-18 | 3 |
B: | 2 | foo | | 2 | 2020-04-22 | 0 |
C: | 3 | bar | | 3 | 2020-04-22 | 1 |
|------------|---------------| |------------|--------------|----------|
「バー」、1、「2020-04-19」、1、「2020-04-19」=>
accountlist data
|------------|---------------| |------------|--------------|----------|
| id | user | | id | allow | upvotes |
|------------|---------------| |------------|--------------|----------|
A: | 1 | admin | | 1 | 2020-04-19 | 3 |
B: | 2 | foo | | 2 | 2020-04-22 | 0 |
C: | 3 | bar | | 3 | 2020-04-22 | 2 |
|------------|---------------| |------------|--------------|----------|
通常は正しく実行されます(オンラインでテスト済み)が、1つではなく2つのステートメントを使用するほうが簡単です。