dポイントプレゼントキャンペーン実施中!

MySQL テーブルの一部のカラムだけを表示させる方法を教えてください

tblAに
 id, a1,a2,a3,a4
のカラムがあった場合、tblA のカラムa3,a4だけを表示したい場合、
 SELECT a3,a4 FROM tblA WHERE
と書けばよいのは分かっています。
ここで質問です。

別のテーブル tblBに
x, y
------
a1,1
a2,3
a3,2
a4,2
というデータがあった場合、カラムa3,a4を「tblBのyが2であるxの値(tblAのカラム名)」としてSELECT文をどう書いたらよいのかがわかりません。
つまり、
 y=2とすれば、a3,a4の意味、
 y>=2 とすれば、a2,a3,a4の意味、
 y=1 とすれば a1 の意味
になるような書き方が知りたいです。

A 回答 (10件)

drop procedure if exists select_a_fromB;


delimiter //
create procedure select_a_fromB(IN operator varchar(20))
begin
set @sql=concat("select group_concat(x) into @a from tbl_b where y",operator);
PREPARE stmt from @sql;
EXECUTE stmt;
set @sql=concat("select ",@a," from tbl_a");
PREPARE stmt from @sql;
EXECUTE stmt;
end
//
delimiter ;

call select_a_fromB(">=2");
    • good
    • 0

テーブル名とか決め打ちで書いているのでご利用の環境とちがっていませんか?


procedureの実行者の権限とか大丈夫ですか?
    • good
    • 0
この回答へのお礼

>テーブル名とか決め打ちで書いているのでご利用の環境とちがっていませんか?
テーブル名はNo2で回答頂いた、tbl_a, tbl_bのままで、中身もそのままです。

>procedureの実行者の権限とか大丈夫ですか?
正直、よくわかりません。何も考えずに、XAMPPをインストール直後のままでの動作確認です。
教科書には、セキュリティのためパスワードをつけろとあったので、一旦はつけたのですが、
XAMPP の phpMyAdmin
が起動しなくなってしまったので、パスワードなしで(インストール直後の状態に戻して)テストしています。

お礼日時:2020/04/08 17:23

#2に補足をつけたようですが、#4を利用してください


また「select @a from tbl_a」はまったく趣旨が異なるので
意味がありません
    • good
    • 0
この回答へのお礼

何度もありがとうございます。
>「select @a from tbl_a」はまったく趣旨が異なるので
了解です。展開して「select a3,a4 from tbl_a;」という文字列にして実行しないと駄目ということですね。

ここまで理解出来たのですが、#4で
 call select_a_fromB("=2");
を実行しても状況は変わらず、何も出力されません。
なお、動作確認はXAMPP の phpMyAdmin の SQL です。

また、コマンドラインから
 select a3,a4 from tbl_a;
を実行した場合と
 set @a='a3,a4';
 set @sql=concat("select ",@a," from tbl_a");
 PREPARE stmt from @sql;
 EXECUTE stmt;
を順番に実行した場合は同じ表示が出ますが、

 call select_a_fromB("=2");
を実行すると、今度は、
ERROR 1370 (42000): execute command denied to user ''@'localhost' for routine 'test.select_a_fromB'
とエラーが表示されてしまいます。
つまり、call select_a_fromB("=2");は、
 phpMyAdmin の SQL では何も出力されない
 コマンドラインではエラーになってしまう
ため、どちらでもうまく行きません。

お礼日時:2020/04/08 16:54

> 考え方がかなりイレギュラー



ちょっといい方が悪かったかもしれません。
お気になさっているようなら申し訳ないです。
「SQLの考え方としてイレギュラー」ということです。
ユーザーが渡せるものはデータだけというのが原則論を伝えたかったのですが
うまくニュアンスが伝わってないですね・・・

ユーザーごとにアクセスを変えるのであれば、
カラムは全て返すとして、アクセスできないはずのでカラムは
nullを返すなど工夫すればSQLライクな書き方になると思います
    • good
    • 0
この回答へのお礼

>「SQLの考え方としてイレギュラー」ということです。
なるほど。正直、SQLの考え方にまだ不慣れですね。どうしてもC言語的に考えてしまいます。
別に気にしているわけではありませんので、ご安心を。
それよりも、ご親切な回答に感謝していますよ。
いろいろとありがとうございます。

お礼日時:2020/04/07 17:11

> 定番の処理はないのでしょうかね。



#1でも触れましたが、考え方がかなりイレギュラーです。
データからカラム名を取ることは一般的な方法ではありません。
プログラム言語によく用意されているプレースホルダー機能(prepare処理)も
テーブル名やカラム名、関数名には利用できません。

ホワイトリストを使って一般的な方法となると、普通はプログラム言語側で
対応することでしょうね
    • good
    • 0
この回答へのお礼

>考え方がかなりイレギュラーです。
技術者には戒め、研究者にはお褒めの言葉ありがとうございます。

>データからカラム名を取ることは一般的な方法ではありません。
カラム名を取りたいのではなく、
 ユーザ毎にアクセスできるカラムを制約したい
だけです。各カラムにアクセスレベルが設定でき、ユーザのアクセスレベルが設定値未満のカラムは、当該ユーザには存在を隠したいのですが、なさそうなので、アクセスレベルを記載したテーブルtblBを用意しておいて、ユーザがアクセス可能なカラムだけを表示させる方法を思いついた訳です。
考え方がかなりイレギュラーなのかしら。

お礼日時:2020/04/07 16:21

結局プロシージャを利用すれば普通のSQLでできない大抵のことを


できてしまいます。
ただそれは汎用性を損なうということなので、プロシージャの多様するなら
仕様書をきっちり作り込む必要がありますし、
ユーザーからのデータ投入に対してサニタイズ、バリデーション処理や
各種例外処理が必要だということを理解した上で対応することになります。
上記リスクとメリット・デメリットを理解した上で、スキルが伴えば
プロシージャがもっとも楽な解決方法になるでしょう
    • good
    • 0
この回答へのお礼

思慮深い回答ありがとうございます。

プロシージャを使うといろんなことができそうですね。
おっしゃる通り、メリット・デメリットを理解することが必要なこと、同感です。

No1>セキュリティ的な課題もありそういう運用はなるべくしないほうが良いと思います
そうなんですね。私は逆に、
利用者ごとに、作業開始直後に、
 利用者が扱えるデータだけを集めた一時テーブルを作り、その一時テーブル上で作業をする
ことで、PHPプログラムの簡素化や安全性向上を期待していますので、使い方を誤ると逆効果ということですね。

対象レコードの抽出はWHERE部で可能ですが、カラムの抽出ができなくて質問しました。
でも操作可能対象だけを取り出す処理は、汎用的と思うのですが、定番の処理はないのでしょうかね。

お礼日時:2020/04/07 09:47

ちなみにphpでやるなら別に全部ぬきだして、必要なところだけ


phpでつまめばいいだけ
また#4のoperatorが不正だった場合や結果が空だったときの
例外処理など結構手を入れないと実用に耐えないでしょう
    • good
    • 0
この回答へのお礼

今回も回答ありがとうございます
https://oshiete.goo.ne.jp/qa/11557860.html

間髪入れずに、デモプログラムを作成いただき、ありがとうございます。

なるほど、
set @sql=concat("select group_concat(x) into @a from tbl_b where y",operator);
で y=2 や y>=2 から、a3,a4 や a2,a3,a4 を@a に読み取り

set @sql=concat("select ",@a," from tbl_a");
で、 SELECT a3,a4 FROM tblA WHERE ・・・
というSQL文を @sql に作文して
 PREPARE stmt from @sql;
 EXECUTE stmt;
で実行するのですね。

>ちなみにphpでやるなら別に全部ぬきだして、必要なところだけ
>phpでつまめばいいだけ
確かにそうとも言えます。
C言語ならなんとかなるのですが、PHPもMySQLもよくわからないので苦労しているところです。どっちで処理したほうが楽なんでしょうかね。

PHPもMySQLも同じくらい不得意なので、
 不要なデータを取得して必要な物を抽出
するより、
 必要な物だけを取得
するほうがエレガントなプログラムの気がしますので、教示くださったデモプログラムを参考に進めて行こうと思います。

ありがとうございました。

お礼日時:2020/04/06 15:40

>  y>=2 とすれば、a2,a3,a4の意味、



あ、わすれてた
    • good
    • 0

一応procedureのサンプルです



//元データ
create table tbl_a(id int primary key,a1 int,a2 int,a3 int,a4 int);
insert into tbl_a values
(1,1001,2001,3001,4001),
(2,1002,2002,3002,4002),
(3,1003,2003,3003,4003);

create table tbl_b(id int primary key,x enum('a1','a2','a3','a4'),y int,unique key(x,y));
insert into tbl_b values
(1,'a1',1),
(2,'a2',3),
(3,'a3',2),
(4,'a4',2);

//procedure 作成

drop procedure if exists select_a_fromB;
delimiter //
create procedure select_a_fromB(IN y int)
begin
set @sql=concat("select group_concat(x) into @a from tbl_b where y=",y);
PREPARE stmt from @sql;
EXECUTE stmt;
set @sql=concat("select ",@a," from tbl_a");
PREPARE stmt from @sql;
EXECUTE stmt;
end
//
delimiter ;

//call
call select_a_fromB(2);
    • good
    • 0
この回答へのお礼

回答ありがとうございます
動作確認したのですが、色々試したのですが、うまく行きません

 select a3,a4 from tbl_a;

 set @a='a3,a4';
 select @a from tbl_a;
では、表示が異なるようです。

何か、勘違いがあるのでしょうか?

お礼日時:2020/04/08 12:05

通常のSQL文ではカラム名をレコードからひっぱることはできません


無理すればプロシージャでできるかもしれまえせんが
セキュリティ的な課題もありそういう運用はなるべくしないほうが良いと思います
    • good
    • 0
この回答へのお礼

回答ありがとうございます

>通常のSQL文ではカラム名をレコードからひっぱることはできません
そうですか、了解です。

となるとPHPの方で、
 SELECT x FROM tblB WHERE y=2;
でデータベースに問いかけて、 a3,a4 を取得し、
この情報を使って
 SELECT a3,a4 FROM tblA WHERE ・・・
というSQL文を作文して呼び出すことになりますね。

方針は決まりましたが、具体的には上に述べた処理をPHPでどのようなプログラムを書いたら良いのかアドバイスいただければ嬉しいです。

お礼日時:2020/04/06 13:54

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!