質問するログイン新規登録

Q&A

解決済

2回答

1258閲覧

SQLでviewAを元にして作ったviewBの値がnullになるときがあります。

dreamers

総合スコア61

SQL

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

MariaDB

MariaDBは、MySQL派生のオープンソースなリレーショナルデータベースシステムです。 また、MySQLとほぼ同じデータベースエンジンに対応しています。

0グッド

0クリップ

投稿2021/06/28 15:19

編集2021/06/29 04:42

0

0

SQLで、viewを元にして作ったviewの値がnullになるときがあります。
何が原因か、ご教授頂きたく、宜しくお願い致します。
(実際につかっているDBはMriaDBで、件数は25000件ほどです)

<例>

概要

A:「Inputテーブル(t1)」と「属性テーブル(t2)」からview「結合テーブル(V1)」を作成。
B:上記view「結合テーブル(V1)」を元に view「最終テーブル(V99)」を作成。
通常は、view「最終テーブル(V99)」は正常に機能していますが、原因不明で値がnullになってしまうことがあり、気が付いた都度、view「最終テーブル(V99)」をDROP して再度CREATEしています。
※view「結合テーブル(V1)」は、常に正常に機能しています。

①view「結合テーブル(V1)」

イメージ説明

SQL

1CREATE VIEW V1 2AS 3SELECT 4t1.DB_id, t1.DB名, t1.id, t2.属性_id, t1.属性名, t1.値, 5FROM `inputテーブル` as t1 6inner join 7属性テーブル as t2 8on t1.属性_id=t2.属性_id 9

②view「最終テーブル(V99)」
イメージ説明

SQL

1CREATE VIEW V99 2AS 3SELECT 4 5id, 6MAX(CASE 属性名 WHEN '名前0' THEN 値 else null END) AS 名前, 7MAX(CASE 属性名 WHEN '住所0' THEN 値 else null END) AS 住所, 8MAX(CASE 属性名 WHEN '年齢0' THEN 値 else null END) AS 年齢 9FROM 10V1 11GROUP BY 12id 13HAVING 14MAX(CASE WHEN DB_id='1' THEN DB名 END) = 'sample' 15

■お尋ねしたいこと

①
MySQLでviewを元にして作ったviewの値がnullになるときがあります。
何が原因か、また、その対応策について、ご教授頂きたく、宜しくお願い致します。

②
viewをもとに、viewをつくることは避けた方がいいのでしょうか
(複雑になるからとかの理由で、、、)
それとも、通常、現場では普通に使う方法なのでしょうか。

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

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

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

gentaro

2021/06/28 21:59

質問文を読む限りだと基本的には動作しているが、条件を変更していないのにある日突然データが取れなくなる、という事? であれば、そのクエリをどのように発行しているのかわからないけど、発行元でエラー発生の有無(有る場合はその内容)を調べたり、RDBMSの側でログを確認したりという事が最初の調査ステップになるんで、それが提示されないと第三者には判断するのが非常に困難だと思うけども。
dreamers

2021/06/29 11:15

gentaro様 ご回答、ありがとうございました。 RDBMSの側でログを確認してみます。
guest

回答2件

0

ベストアンサー

V1の結果がキャッシュされていれば、そのような事は起きるかもしれません。
なので、V1経由のビューではなく、V1を展開した形でのV99を作成した方が良いでしょうね。

投稿2021/06/29 03:56

sazi

総合スコア25440

dreamers

2021/06/29 04:26

sazi様 ご回答ありがとうございます。 私的には、V99は、めまいがするほど、複雑です。 V1を展開した形でのV99を作成、となると、一体どうしたらいいことやら、、、 ヒントをご教示いただけますと、嬉しいです。
sazi

2021/06/29 04:47 編集

MariaDBが10.2.1以降なら、with式にV1の内容を展開すればいいので、そこまで手は掛からないと思います。 もう一つの方法は、一時テーブルにV1の内容を出力して、それを参照するようにする。 あくまで、v1の結果を出力するのに掛かる時間の影響が無いならですが。
sazi

2021/06/29 05:08 編集

もし、有効になっている様なら、query_cache_typeを変更し、SQL_NO_CACHEオプションを付けてみてください。 https://dev.mysql.com/doc/refman/5.6/ja/query-cache-in-select.html ※当然キャッシュの恩恵は受けれなくなるので、遅くなるという事にはなりますが。
dreamers

2021/06/29 10:08

sazi様 ご回答ありがとうございます。 ・MariaDBが10.3.29でした。 ・with式にV1の内容を展開してviewを作成する具体的情報がなかなか見つかりません。 CREATE VIEW V99 AS SELECT id, MAX(CASE 属性名 WHEN '名前0' THEN 値 else null END) AS 名前, MAX(CASE 属性名 WHEN '住所0' THEN 値 else null END) AS 住所, MAX(CASE 属性名 WHEN '年齢0' THEN 値 else null END) AS 年齢 FROM ※以降viewV1の展開? with v1 AS (SELECT t1.DB_id, t1.DB名, t1.id, t2.属性_id, t1.属性名, t1.値, FROM `inputテーブル` as t1 inner join 属性テーブル as t2 on t1.属性_id=t2.属性_id) ※ここまでviewV1の展開? GROUP BY id HAVING MAX(CASE WHEN DB_id='1' THEN DB名 END) = 'sample' とかでも、無いようだし、、、 ・have_query_cacheがyesだったので、V1とV99のselectにSQL_NO_CACHEオプションを付けてみました。 若干遅くなった感じがしますが、許容範囲の感じがしてます。 with式にV1の内容を展開してviewを作成する具体的方法のアドバイスをご教授いただければ、嬉しいです。
sazi

2021/06/29 10:23 編集

SQL_NO_CACHEオプションで解決するなら、WITH式での展開は不要だと思います。 withを使用した記述は以下の様なものです。 CREATE VIEW V99 AS with v1 as (v1の中身) select ~ -- V99の中身
dreamers

2021/06/29 11:42 編集

sazi様 誠に、ご回答ありがとうございました。 本当に、助かりました。 SQL_NO_CACHEオプション、with句、別々に試してみました。体感的には同程度の速さでした。 一応、SQL_NO_CACHEオプションのほうで、運用していこうと思っています。 ※ V1: SQLアンチパターンとされるEAV形式(縦表示)の複数テーブルを結合して最終形のテーブル作成 V99: VIを横形式のテーブルとして作成 このV1➡V99は、実務現場では多い作業だと思いますが、この過程を、キャッシュ等の不安定克服も含めて説明した情報があまりないのが、不思議な感じでした。
sazi

2021/06/29 13:56 編集

SQLアンチパターンを敢えて使う場合の方法なんて、情報が少ないのは当然という気がします。 今回はSQLアンチパターンというところまで踏み込んだ所では無く、Viewを使った場合の不備という事ですから、DBMSの仕様を確認すべきでしょうね。 因みに、with式(CTE)は可読性を高めるというのもあるんですが、SQL内ではキャッシュされるので性能向上にも貢献します。
dreamers

2021/06/30 13:45

sazi様 ありがとうございました。 アドバイスいただきましたwith式(CTE)のSQL内でのキャッシュも考えて、こちらを採用してしばらく様子をみてみようと思います。 sazi様のおはなしすべてから、息を呑むほどの実務現場のプロの熱気が伝わってくるかのようでした。 このたびは、本当にありがとうございました。
guest

0

ぱっとみたところFROMの前の , が余計なのでエラーになります。

MAX(CASE 属性名 WHEN '年齢0' THEN 値 else null END) AS 年齢,
FROM

現象を再現できるようにテーブル定義はCREATE TABLE文で、テーブル中のデータはINSERT文で Markdown の [コード] に修正できるとSQLの動作確認が容易になるので、適切なコメントが付き易くなります。

投稿2021/06/28 19:53

Orlofsky

総合スコア16421

dreamers

2021/06/29 03:17

ご回答ありがとうございます。 すいません、再度確認しましたら、FROMの前の , は本番の記載では元々つけていなかったです。 申し訳ございません。 今後、ご指摘して頂いた通り、現象を再現できるようにテーブル定義はCREATE TABLE文で、テーブル中のデータはINSERT文で Markdown の [コード] に記載するようにいたします。 今後、サーバー側・DB側でのエラーログを調べてみようと思います。 ちなみに、viewAを作成し、そのviewAをもとに、viewBを作成することは、実務上、通常の作業なのでしょうか。
Orlofsky

2021/06/29 05:19

質問は修正できます。 「今後」って書く人は今後でも改めない事が多いです。 CREATE TABLEやINSERTを提示すると動作確認してくれる人が多くなります。
dreamers

2021/06/29 11:37

Orlofsky様 ご回答ありがとうございます。 当方、恥ずかしながら、CREATE TABLEやINSERTなど、SQL文を作成したことがほとんどなく、今しばらく時間がかかりそうですが、書き上げて、質問を必ず訂正させていただきます。 このたびは、お忙しい中、誠にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.25%

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

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

質問する

関連した質問