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

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

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

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

phpMyAdmin

phpMyAdminはオープンソースで、PHPで書かれたウェブベースのMySQL管理ツールのことです。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

1回答

825閲覧

SQL文で not in をつなげると、結果がなくなってしまいました

ikatako

総合スコア270

MySQL

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

phpMyAdmin

phpMyAdminはオープンソースで、PHPで書かれたウェブベースのMySQL管理ツールのことです。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

1クリップ

投稿2020/02/02 13:19

編集2020/02/02 13:22

###実現したいこと
block、follow、favoriteというアクションが詰まったaction_datasというテーブルがあるのですが、そこからユーザーリストを取得するときに、block関係にあるユーザーを除外するSQLを書きたいです。

###発生している問題
「➀followとfavoriteのユーザーリスト」を取得するSQLは別の機会で教えて頂いたものがあります。これは問題ありません。

そして「➁block関係にあるユーザーリスト」を取得するSQLもなんとか自分で書けました。

しかし、➀から➁を除外すべくnot inでつなげると、何も取得されなくなってしまう状況です。

###検索対象となるテーブル(action_datas)
まず検索対象となるテーブルaction_datasの作成コードになります。

SQL

1# action_datas の作成 2CREATE TABLE action_datas 3 (`action_id` int, `action_name` varchar(8), `action_date` varchar(4), `actor_id` int, `target_id` int, `target_type` varchar(6)) 4; 5INSERT INTO action_datas 6 (`action_id`, `action_name`, `action_date`, `actor_id`, `target_id`, `target_type`) 7VALUES 8 (1, 'block', '1月1日', 1, 2, 'user'), 9 (2, 'follow', '2月2日', 1, 20, 'thread'), 10 (3, 'follow', '3月3日', 2, 20, 'thread'), 11 (4, 'favorite', '4月4日', 3, 2, 'user'), 12 (5, 'follow', '5月5日', 3, 20, 'thread'), 13 (6, 'favorite', '6月6日', 1, 3, 'user'), 14 (7, 'block', '7月7日', 1, 4, 'user'), 15 (8, 'follow', '8月8日', 4, 20, 'thread'), 16 (9, 'block', '9月9日', 2, 1, 'user') 17;

###➀followとfavoriteのユーザーリスト
そして下記は「➀followとfavoriteのユーザーリスト」です。

(サイト閲覧者が1で、閲覧中のスレッドが20という設定なので、actor_id=1target_id=20となっています。)

ここからblock関係のユーザーの除外を実現したいので、コメントアウトしてる部分を実装できればと思っています。

SQL

1 select follow.actor_id 2 , max( 3 case when action.action_name='follow' then action.action_date end 4 ) as follow_date 5 , max( 6 case when action.action_name='favorite' then action.action_date end 7 ) as favorite_date 8 from action_datas follow 9 left join action_datas action 10 on follow.actor_id=action.target_id 11 and action.actor_id=1 and action.target_type='user' 12 where follow.target_type='thread' and follow.target_id=20 13 14 /* 15 # 1とblock関係にあるユーザーを除外 16 not in( 17 18 ) 19 */ 20 21 group by follow.actor_id

###➁block関係にあるユーザーリスト
続いて自分で書いたものなのでおかしな点があるかもしれませんが、「➁block関係にあるユーザーリスト」が下記になります。

一応、先のテーブルaction_datasから、1をblockしている2と、1がblockしている4が取得できる状況です。

SQL

1 # 1をblockしているユーザーを取得 2 select block.actor_id 3 from action_datas block 4 where block.target_type='user' and block.target_id=1 and action_name='block' 5 group by block.actor_id 6 # 1がblockしているユーザーをunionする 7 union 8 select target_id 9 from action_datas 10 where action_name='block' and actor_id=1

###試したこと
「➀followとfavoriteのユーザーリスト」のコメントアウトしてる部分に「➁block関係にあるユーザーリスト」を記載すると、何も取得できなくなってしまいました。

こちらのSQL fiddleで試していただけます。

そしてnullがある場合に取得できなくなるという例を見つけまして、「➀followとfavoriteのユーザーリスト」にはnullが入るからそれが原因かと思いis not nullを加えてみたのですがやはり何も取得できず、先に進めなくなってしまいました。

ご助力願えましたら幸甚に存じます。
どうぞ宜しくお願い致します。

###補足情報(FW/ツールのバージョンなど)
phpMyAdmin(4.8.5)で、MySQL(10.0.33-MariaDB)を使っています。

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

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

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

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

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

guest

回答1

0

ベストアンサー

in で使用するサブクエリーはunionマージやgroup byするとコストが掛かるので、極力使用しない方がいいですね。結果は同じですから

SQL

1select follow.actor_id 2 , max( 3 case when action.action_name='follow' then action.action_date end 4 ) as follow_date 5 , max( 6 case when action.action_name='favorite' then action.action_date end 7 ) as favorite_date 8from action_datas follow 9 left join action_datas action 10 on follow.actor_id=action.target_id 11 and action.actor_id=1 and action.target_type='user' 12where follow.target_type='thread' and follow.target_id=20 13 and follow.actor_id not in( 14 select case when target_id=1 then actor_id else target_id end 15 from action_datas 16 where target_type='user' and action_name='block' and 1 in (target_id, actor_id) 17 ) 18group by follow.actor_id

投稿2020/02/02 15:04

sazi

総合スコア25327

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

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

ikatako

2020/02/02 15:57 編集

質問のコードは 「not in()」 ではなく 「and follow.actor_id not in()」 でできたのですね。 しかしその変更だけではかっこ内のコストが高いとのことで、別の案をありがとうございます。仰るように致します。 恐れ入りますが、もしよろしければこの初心者に2点教えて頂けませんでしょうか。 【1点目】 「not in()」から「and follow.actor_id no in()」とすることは、どんな意味なのでしょうか? 【2点目】 not in() のかっこ内のコードについて下記のように翻訳してみたのですが、この最後の行がわかりません。 1 in (target_id, actor_id) は、どんな意味なのでしょうか
ikatako

2020/02/02 15:49

/* not in() のかっこ内のコードをコメントアウトで翻訳 */ # target_id=1ならactor_idを表示し、1以外ならtarget_idを表示する # つまり自分がblock対象ならその実行者を表示し、自分がblockする側ならblock相手を表示するということ select case when target_id=1 then actor_id else target_id end # 検索テーブルは action_datas を指定する from action_datas # action_datas の中から user かつ block かつ where target_type='user' and action_name='block' and # こちらの 1 in (target_id, actor_id) は、どんな意味なのでしょうか 1 in (target_id, actor_id)
sazi

2020/02/02 16:10

in句の構文は通常、A in (B)です。(否定の場合は A not in (B)) 質問の記述は、Aが指定されていないので文法エラーです。 AやBはカラムや値を指定します。Bは値の列挙が可能です。 1 in (target_id, actor_id)は (target_id=1 or actor_id=1)と同義です。
sazi

2020/02/03 07:25 編集

サブクエリーは多用していると、遅い場面にあたることがありますから気を付けて下さい。 なぜMySQLのサブクエリは遅いのか。(http://nippondanji.blogspot.com/2009/03/mysql_25.html ) 記事は古いので、以降のバージョンでは改善されているかもしれませんが。
ikatako

2020/02/02 17:34

なるほど。少しずつですがわかってきました。いつもありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問