質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

2回答

645閲覧

UNSIGNED なカラムに対し、「0のときは引き算をしない」

nikuatsu

総合スコア177

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

1クリップ

投稿2022/09/04 06:14

編集2022/09/04 06:39

実現したいこと

MySQL 5.7 でUNSIGNEDなカラムに対し、「0のときは引き算をしない」ようにする方法を知りたいです。

該当のソースコード

よくある「いいね」機能です。

現状は以下のように ID = 1 のレコードの count_likes カラムを、足し算|引き算しています。(実際はエスケープしています。)

php

1// like|unlikeした対象の投稿ID 2$id = $_POST['id']; 3 4// 現状が unlike なら like したということなので '+' し、逆なら '-' する 5$puramai = $_POST['like_state'] === 'unlike' ? '+' : '-'; 6 7// 足し算|引き算 8$sql = " 9 UPDATE comments 10 SET count_likes = count_likes {$puramai} 1 11 WHERE ID = {$id} 12";

発生している問題

しかし count_likes カラムは UNSIGNED なので、0のときに引き算してしまうとエラーになってしまいまして…

避けるためにはどのようなクエリがよろしいでしょうか?

試そうとしたこと

きっと CASE WHEN でできるのでは?と考えてはいるのですが、これ↓ではありませんよね…

これでは「count_likesが0のときは、必ず0」になってしまうので、なんとかうまいこと「count_likesが0のとき、かつ $puramai が '-' のときは、必ず0」のような記述はできないものでしょうか?

php

1$sql = " 2 UPDATE comments 3 SET count_likes = CASE 4 WHEN count_likes = 0 5 THEN 0 6 ELSE count_likes {$puramai} 1 7 END 8 WHERE ID = {$id} 9";

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

「count_likesが0のとき、かつ $puramai が '-' のときは、必ず0」のような記述はできないものでしょうか?

CASTした結果でマイナスなら0に置き換えるようなCASE式にすれば良いと思います。

以下参考
UNSIGNEDなカラムの演算でマイナス値になるとエラーになる

だけど、保持する項目はUNSIGNEDとせず、表現する際に0で打ち止めとする方が良い気がしますね。

投稿2022/09/04 08:38

編集2022/09/04 16:29
sazi

総合スコア25173

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nikuatsu

2022/09/04 08:50

sazi様データべ―ス系最強ですね。いつもなんでもよくご存知で…脱帽です。 そういえば「表現する際に0で打ち止め」でもいいかもと思えてきました。 ぴったりのご回答を2つも、誠にありがとうございます。助かりました。
guest

0

そもそも論として、「いいね付けた人以外が取り消せる」という構造そのものが間違いだと思います。

「誰がどの記事につけた」というのを記録しておいて、付けた本人だけがそれを取り消せる、というのがまっとうな構造だと考えます。

投稿2022/09/04 06:46

maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nikuatsu

2022/09/04 07:08

いえ、仕様次第だと思います。本人のいいねはローカルストレージにあるので「自分がどの記事につけた」は確認できます。そしてサーバーのデータはものすごくざっくりとした大体の目安にしか使いませんので count_likes は誰がどうつけても構いません。
maisumakun

2022/09/04 07:15 編集

> そしてサーバーのデータはものすごくざっくりとした大体の目安にしか使いませんので count_likes は誰がどうつけても構いません。 なら、でたらめになってマイナスになるのも許容するぐらいのおおらかさでやっておきましょう。 「誰がどうつけても構」わないということは、悪意のある攻撃者にとっても操作し放題の、何の意味もない値に成り下がってしまっています。
nikuatsu

2022/09/04 07:14

まぁでたらめというのは極端ですが、うっかりマイナスにもなりえるくらいのざっくりなんですよね。で、さすがにそれは避けておこうというのが質問の意図なのです。やはり難しいですか?
maisumakun

2022/09/04 07:18

> やはり難しいですか? そんな値なら、記録する機能性そのものを付けるべきではありません。攻撃者の遊び場になるだけで有害無益です。
nikuatsu

2022/09/04 07:24

そうでしょうか?実際に大手ブログのnoteや、他にも多くのサービスにおいて、いくらでもいいねができる仕様になっていますが…(もちろん極端なリクエストを防ぐべくIPアドレスくらいは保存して対策しているでしょうけれど) この点はいかが思われますか?
maisumakun

2022/09/04 07:26 編集

> いくらでもいいねができる仕様になっていますが… 最低限、同じセッションからは1回だけのいいねになっているはずです。他人のいいねを減らすような手段はありません。
maisumakun

2022/09/04 07:30

localStorageでいいねを管理するのであれば、それは純粋にブラウザ内の世界にとどめて、合計数は管理もしない、というのが妥当だと考えます。
nikuatsu

2022/09/04 07:43

うーん、まだよくわからないです。 例えばコメントとそれへいいねした人を、次の「いいね履歴テーブル」へ保存しますよね。 「いいね履歴テーブル」 ID, コメントID, セッション 1, 1, 'hra' 2, 2, 'kdt' 3, 1, 'jdt' 4, 5, 'plt' そしてコメントはまぁ次の「コメントテーブル」だとします。 「コメントテーブル」 ID, comment, count_likes 1, 'こんにちは', 10 2, 'さようなら', 20 コメントをいいね順でソートし SELECT する場合、「いいね履歴テーブル」に毎回 COUNT() をかけるのは非効率なので、普通は「コメントテーブル」の count_likes のような集計済みのカラムを ORDER BY に使うと思います。 さて、この count_likes の足し引きにおいて「誰がしたか」を区別する意味はあるのでしょうか? いいねのリクエストがあったとき、「いいね履歴テーブル」に「誰がしたか」を保存するのはもちろんいいのですが、だとしても、とりあえず count_likes を足し引きしますよね? この足し引きにおいて、「誰がしたか」は不要ではないか?質問の状況がありうるのではないか?と問うているのですが… 改めてこの点いかがでしょうか?
maisumakun

2022/09/04 07:46 編集

> 例えばコメントとそれへいいねした人を、次の「いいね履歴テーブル」へ保存しますよね。 localStorageはどこへ行ったのですか? localStorageでそれぞれのユーザーが分散的にいいねのデータを持っている状態と、誰がどの記事にいいねしたかをDBサーバで持っている状態とでは、全く前提条件が異なります。
maisumakun

2022/09/04 07:49

> とりあえず count_likes を足し引きしますよね? キャッシュだけ破棄して、必要になれば再計算、という手段もありますし、マテリアライズドビューを使って集計結果にインデックスをかける手段も、RDBMSによってはありえます。
nikuatsu

2022/09/04 08:03

> localStorageはどこへ行ったのですか? えっと、あなたの前提に沿ったのですけど…、、議論領域を正しく整理してください。 沿った上で count_likes のようなカラムに「誰がしたか」を区別する意味を問うているのです。 > キャッシュだけ破棄して、必要になれば再計算、という手段もありますし、マテリアライズドビューを使って集計結果にインデックスをかける手段 なるほど、全ての手段を知らず大変勉強になりました。しかし他方で、count_likes というカラムを設ける手段も一般的に行われているかと存じますし、質問はこの手段です。 改めて、count_likes のようなカラムに「誰がしたか」を区別する意味をお伺いしたいのです。 整理しましょう。質問当初の前提では localStorage に保存するために「誰がしたか」は不要という考えを述べました。対してあなたは「誰がしたか」は必要でありセッションによる区別という手段をご提案されました。そこで私は、その前提に沿いセッションによる区別を行ったとしても、 count_likes のようなカラムに「誰がしたか」は介在しないだろうという問いを 2022/09/04 16:43 で述べた。というところです。
maisumakun

2022/09/04 08:16 編集

> count_likes のようなカラムに「誰がしたか」を区別する意味をお伺いしたいのです。 減算処理は、あくまで効率化のための都合であり、ユーザーの操作とははなから無縁なものと考えていましたので、このような解釈をしているのが想定外でした。「他人のいいねを減らすような手段はありません」というのは、ユーザーといいねのテーブルの処理について言及したもので、合計数の処理とは無縁な話のつもりでした。
maisumakun

2022/09/04 08:18 編集

> 質問当初の前提では localStorage に保存するために「誰がしたか」は不要という考えを述べました。対してあなたは「誰がしたか」は必要でありセッションによる区別という手段をご提案されました。 その時点で誤読です。2022/09/04 16:30の回答の通り、localStorageに保存するなら「集計そのものに意味がない」というのが一貫した趣旨の回答です。 上述しましたが、「セッションによる区別」はあくまでユーザーといいねのテーブルの識別用であって、count_likeと関連付けることは、想定すらしていませんでした。
nikuatsu

2022/09/04 08:31

なるほど。お詫び申し上げます。 質問はまさに仰るとおり「合計数の処理」ですね。 私は「localStorageでも集計に意味があると思う派」なので、引き続き良い方法がないか探してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問