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

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

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

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

SQL

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

PHP

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

Q&A

解決済

2回答

733閲覧

MySQLクエリに改行をつけたい

ThouShaltNot

総合スコア3

MySQL

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

SQL

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

PHP

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

0グッド

0クリップ

投稿2023/08/11 20:26

下記のコードのようにクエリに改行をつけて整形したいのですが、良い方法はないでしょうか?

自分ではこうして大文字での正規表現で考えたのですが、そもそも予約語リストとかを使った方がいいでしょうし、その予約語が例えばINSERTされる値としての使用の意図なのかなどのチェックも必要であることに気づき、自力では無理だと思いました。

もちろん今その機能を書いてくださいなどとは申しませんが、先人のライブラリだとか、ツールだとか、何か良い方法があれば知りたいです。

php

1<?php 2 3function transformQuery($queryString, $orderByField = 'name') { 4 // クエリ文字列を大文字に変換して解析 5 $upperQueryString = strtoupper($queryString); 6 7 if (strpos($upperQueryString, 'SELECT') === 0) { 8 // SELECT文の場合 9 $pattern = "/SELECT\s*(.*?)\s*FROM\s*(.*?)\s*(WHERE\s*.*?)?\s*(ORDER BY\s*.*?)?$/i"; 10 preg_match($pattern, $queryString, $matches); 11 12 if (count($matches) >= 3) { 13 $fields = trim($matches[1]); 14 $table = trim($matches[2]); 15 $conditions = isset($matches[3]) ? trim($matches[3]) : ''; 16 $orderBy = isset($matches[4]) ? trim($matches[4]) : ''; 17 18 // 新しいクエリを生成して返す 19 $newQuery = "SELECT\n{$fields}\nFROM\n{$table}\n"; 20 21 if (!empty($conditions)) { 22 $newQuery .= "WHERE\n{$conditions}\n"; 23 } 24 25 if (empty($orderBy)) { 26 $newQuery .= "ORDER BY {$orderByField}"; 27 } else { 28 $newQuery .= "{$orderBy}"; 29 } 30 31 return $newQuery; 32 } 33 } elseif (strpos($upperQueryString, 'INSERT') === 0) { 34 // INSERT文の場合 35 $pattern = "/INSERT\s+INTO\s+(.*?)\s+\((.*?)\)\s+VALUES\s+\((.*?)\)/i"; 36 preg_match($pattern, $queryString, $matches); 37 38 if (count($matches) >= 4) { 39 $table = trim($matches[1]); 40 $columns = trim($matches[2]); 41 $values = trim($matches[3]); 42 43 // 新しいクエリを生成して返す 44 $newQuery = "INSERT INTO {$table} ({$columns})\nVALUES ({$values})"; 45 46 return $newQuery; 47 } 48 } elseif (strpos($upperQueryString, 'UPDATE') === 0) { 49 // UPDATE文の場合 50 $pattern = "/UPDATE\s+(.*?)\s+SET\s+(.*?)\s+WHERE\s+(.*)/i"; 51 preg_match($pattern, $queryString, $matches); 52 53 if (count($matches) >= 4) { 54 $table = trim($matches[1]); 55 $setClause = trim($matches[2]); 56 $conditions = trim($matches[3]); 57 58 // 新しいクエリを生成して返す 59 $newQuery = "UPDATE {$table}\nSET {$setClause}\nWHERE {$conditions}"; 60 61 return $newQuery; 62 } 63 } elseif (strpos($upperQueryString, 'DELETE') === 0) { 64 // DELETE文の場合 65 $pattern = "/DELETE\s+FROM\s+(.*?)\s+WHERE\s+(.*)/i"; 66 preg_match($pattern, $queryString, $matches); 67 68 if (count($matches) >= 3) { 69 $table = trim($matches[1]); 70 $conditions = trim($matches[2]); 71 72 // 新しいクエリを生成して返す 73 $newQuery = "DELETE FROM {$table}\nWHERE {$conditions}"; 74 75 return $newQuery; 76 } 77 } 78 79 return $queryString; // 変換できないクエリはそのまま返す 80} 81 82// 使用例 83$originalQuery1 = "SELECT id, name, age FROM users WHERE age > 18 AND name LIKE 'John%'"; 84$transformedQuery1 = transformQuery($originalQuery1); 85echo $transformedQuery1 . "\n\n"; 86 87$originalQuery2 = "INSERT INTO orders (order_date, total_amount) VALUES ('2023-08-12', 150.50)"; 88$transformedQuery2 = transformQuery($originalQuery2); 89echo $transformedQuery2 . "\n\n"; 90 91$originalQuery3 = "UPDATE employees SET salary = salary * 1.1 WHERE department = 'Sales'"; 92$transformedQuery3 = transformQuery($originalQuery3); 93echo $transformedQuery3 . "\n\n"; 94 95$originalQuery4 = "DELETE FROM products WHERE stock_quantity <= 0"; 96$transformedQuery4 = transformQuery($originalQuery4); 97echo $transformedQuery4 . "\n\n"; 98

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

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

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

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

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

guest

回答2

0

ベストアンサー

SqlFormatterというのを作っている人がいます。

こういうものを参考にして、自分の欲しい機能を作成されればよいのではないでしょうか (それか自分でコードを書かずにこれを使うことにするか)。


【2023-08-14追記】

yambejp さんのご回答 に対して。

データベースサーバはまさにその「作成済みのクエリ―の評価」をしていますので、それをプログラミングで実現すること自体は可能であるはずです。

また、次のような理由でクエリの整形自体は挑戦しがいのあるテーマとも思いますので、「無意味」と言い切るのもどうかと思います。

質問者さんが質問当初考えていらっしゃったような「正規表現を使ってキーワードの境界を識別する」という方法に限界があるのは明らかです。正規表現では通常、SQLをはじめとするプログラミング言語を表現できるほどの複雑なテキストパターンを扱えないからです。一部の環境でサポートされるいわゆる「拡張正規表現」を使えばできるときもありますが、大変分かりにくく使いにくいものです。

つまり簡単に言うと、正規表現というのは (初心者向けの解説でしばしばそう言われているような) 万能なものでも自由なものでもないのです。ある程度複雑なことをやろうとするならば、むしろ正規表現を使うことは控えたほうがよいです。

SQLのクエリなどのプログラミング言語のテキストを正しく評価するには、「トークン化」(tokenize) と「構文解析」(parse) という2段階の処理が必要です。たとえばカラム名がかりに「TEST FROM」という特殊なものだったときでも、それをひとつのトークンとして識別できれば、それを含むクエリを正しく解析できます。

上で紹介したSqlFormatterは、まさにこれをやっています。トークン化を行ってから、構文規則に基づいて整形やシンタックスハイライティングをしています。そのため、特殊なカラム名なども文法的に正しく表記されていれば正しく扱えます。こういったことは正規表現だけでは実現できないことです。

このようなものを参考にして、質問者さんがやりたいことを実現してみていただきたいです。

投稿2023/08/11 22:07

編集2023/08/14 03:39
ikedas

総合スコア4443

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

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

ThouShaltNot

2023/08/14 22:54

まさに求めていたライブラリです。ありがとうございました!利用させて頂きます!
guest

0

作成済みクエリーを評価するのは運用上もあまり意味がないので単なる改行による整形ツールという位置づけでよいのでしょうか?であれば、予約語を利用して整形するのが妥当でしょう。
ただしカラム名がかりに「TEST FROM」という特殊なものだったときこれも「TEST\nFROM」になるのは仕方がないことです。つまりこれが作成済みのクエリーの評価の無意味なところです。

PHP

1<?PHP 2function transformQuery($sql){ 3 $pattern=[ 4 "/(?<=SELECT)\s+/i", 5 "/\s+(?=FROM)/i", 6 "/\s+(?=WHERE)/i", 7 "/\s+(?=ORDER\s+BY)/i",]; 8 return preg_replace($pattern,"_\n_",$sql); 9} 10$q1 = "SELECT id, name, age FROM users WHERE age > 18 AND name LIKE 'John%' ORDER BY id ASC"; 11$r1 = transformQuery($q1); 12print nl2br($r1).";<br>\n"; 13$q2 = "SELECT id,`TEST FROM`, age FROM `TEST WHERE` WHERE age > 18 AND name LIKE 'John%' ORDER BY id ASC"; 14$r2 = transformQuery($q2); 15print nl2br($r1).";<br>\n";

追記

ikedasさんからの批判について
フレームワークがクエリービルダーを採用しているように、運用上生のSQL文はトラブルの原因になりがちなため、テーブル名や比較処理など明示的にあたえることが肝要です。もちろん自分で一から書くSQL文の場合組み立て時点で評価できるのでさほど問題はありませんし、値はprepareで渡すのでインジェクションも起きづらいので問題ないでしょう。ただ命題のようにすでにできあがっているSQL文を評価・整形することは無駄しかないのでやめたほうがいい(=無意味)というのが私見です。とはいえThouShaltNotさんやikedasさんがテキストとしての生のSQL文を重要視しているのであればそれを否定するものではありませんし、その部分については先の回答で肯定的に回答を上げているつもりです。
例はよくありませんがイメージとしてはevalで実行させたいPHP文を、実行前に有効かどうか評価すべきか・・・的な話で、私は評価するなんて無駄(=無意味)なぜならevalなんて使わないから、という考え方です。
極端な例で恐縮ですが参考までに以下

SQL

1create table `select test from tbl`(id int primary key,`select test from tbl` varchar(100)); 2insert into `select test from tbl` values 3(1,'test'), 4(2,'select test from tbl'), 5(3,'select test from tbl where 1'), 6(4,'select test from tbl'); 7 8create table `select test from tbl where 1` (id int primary key,`select test from tbl` varchar(100)); 9insert into `select test from tbl where 1` values 10(1,'select test from tbl'), 11(2,'select test from tbl'), 12(3,'select test from tbl where 1');

としたとき、以下のSQL文は有効ですが、テキストとして評価をすべきかというと疑問です

SQL

1select `select test from tbl` as '`select test from tbl where 1' 2from `select test from tbl` as `select test from tbl where 1` 3inner join `select test from tbl where 1` as ```select test from tbl``` 4using (`select test from tbl`) 5where `select test from tbl`='select test from tbl' 6order by `select test from tbl`

投稿2023/08/14 00:34

編集2023/08/15 01:12
yambejp

総合スコア117650

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

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

ThouShaltNot

2023/08/14 22:55

ありがとうございます!質問のコードよりだいぶ良いですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.31%

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

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

質問する

関連した質問