SQL質疑応答スレ 11問目

このエントリーをはてなブックマークに追加
937NAME IS NULL:2011/09/18(日) 18:52:45.40 ID:???
???
938NAME IS NULL:2011/09/18(日) 19:04:23.67 ID:???
テーブルに最終更新日時の列を追加しといて
トリガーで更新するとかしとかないと無理
939NAME IS NULL:2011/09/18(日) 19:04:50.16 ID:???
えっと・・・
id score1 score2 score3
--------------------------
1 10 10 10
2 20 10 10
3 30 10 10
このデータを
id3の人が2011-0906にWEB上で編集して
id2の人も2011-0905にWEB上で編集した。
id1の人がまったく更新していないとして・・・
id score1 score2 score3
--------------------------
3 30 10 10
2 20 10 10
1 10 10 10
こういう順番で出すようにしたいんですが 可能ですか?
940NAME IS NULL:2011/09/18(日) 19:11:32.94 ID:???
>>938
作らないとだめですか・・・わかりました。
ありがとうございます
941NAME IS NULL:2011/09/18(日) 23:24:36.64 ID:Zw+0oaRW
DBMS : Mysql

説明
データは10万件あると想定します。
挿入する際に一つのワードを二つのカラムに大して重複チェックを行いたいです。
どちらか片方にそのワードが含まれていたらcountで0を返す結果が欲しいです。

select count(*) from table where colA = 'ワード' OR colB = 'ワード'
これだと現在2秒程度かかるので高速化したいです。

よろしくお願いします。
942NAME IS NULL:2011/09/18(日) 23:30:16.39 ID:???
Union
943NAME IS NULL:2011/09/18(日) 23:41:22.00 ID:???
>>942
同じテーブル内にAとBがあります。
それでもUnionの使い方によっては早くなりますか?
944NAME IS NULL:2011/09/18(日) 23:42:48.18 ID:???
それはやってみて試すしかない。
945NAME IS NULL:2011/09/18(日) 23:44:18.13 ID:???
頻繁にinsertするならチェック用に別テーブル作るのが一番よさげだけど
946NAME IS NULL:2011/09/18(日) 23:57:58.66 ID:???
>>944
concatならまだわかりますけどUnionならどう使えばいいのでしょうか?
ちなみにconcatではあまり速度は変わりませんでした。

>>945
チェック用の別テーブルとはどのように構築すれば良いのでしょうか?
現在挿入されているものは全てユニークなものになっているので行数は減らないです。
947NAME IS NULL:2011/09/19(月) 00:01:00.54 ID:???
COLA と COLB のデータ両方がひとつのカラムに入ったテーブル。
OR を使わなくていいんで速い。
948NAME IS NULL:2011/09/19(月) 00:07:16.59 ID:???
select cola from table union select colb from table
が10万件より劇的に減るなら効果ありそうだけど、難しそうだな
949NAME IS NULL:2011/09/19(月) 00:16:35.65 ID:???
>>947
あー、なるほど。
件数的には19万程度になると思うので微妙だと思います。

ただ、ちょっと追加情報になってしまうのですが、AかBのどちらかがNULLになってることが多いです。
この場合何かいい方法ってありますか?
950NAME IS NULL:2011/09/19(月) 00:21:14.59 ID:???
ならやっぱり、cola、colbにそれぞれインデックスはってunionなのかな
951NAME IS NULL:2011/09/19(月) 00:21:18.73 ID:???
まず言われたことやれよハゲ
952NAME IS NULL:2011/09/19(月) 00:35:14.92 ID:4PlpFPwP
>>950
http://labs.unoh.net/2007/06/mysql5.html
ではこの当たりが参考になりそうなのでこれで少し検証してみます。
ありがとうございました。
953NAME IS NULL:2011/09/19(月) 00:44:38.24 ID:???
よろしくお願いします

MySQLでint型でstartとendというフィールドがあります。start < endとなっています。
n以上m以下の範囲が、テーブルのstart以上end以下の範囲と被ってるレコードを取り出す場合、
SELECT文の条件はどうなるのでしょうか?

954NAME IS NULL:2011/09/19(月) 01:03:29.11 ID:???
>>950
一応報告まで。
Deleteを使用しているためIndexの再生成に時間がかかりすぎてしまうようです。
もうSQLどうこうの前に構造レベルでの変更が必要のようです。
ただ、貴重な意見がいただけました。
変更した際はUnionを使う方法でやりたいと思います。

ありがとうございました。
955NAME IS NULL:2011/09/19(月) 01:11:58.15 ID:???
>>953
被ってるってどういうこと?
n以上m以下とstart以上end以下の範囲がちょっとでも重なってればいいのか
n以上m以下がstart以上end以下にすっぽり収まるのかその逆なのか
956NAME IS NULL:2011/09/19(月) 02:07:55.09 ID:???
>>955
ありがとうございます
ちょっとでも重なるほうでおねがいしたいです
957NAME IS NULL:2011/09/19(月) 02:25:40.24 ID:???
>>956
where (n > start and n < end) or (m > start and m < end)
でいけるんじゃね
958NAME IS NULL:2011/09/19(月) 04:04:24.69 ID:???
>>941
ちょっと確認するけど、
「どちらか片方にそのワードが含まれていたらcountで0を返す結果が欲しいです。」
これは間違いだよね?
959958:2011/09/19(月) 04:07:39.31 ID:???
>>958
ごめんなさい。この質問の方が間違い。
960NAME IS NULL:2011/09/19(月) 06:12:02.08 ID:???
>>953
start < m and end > n
961NAME IS NULL:2011/09/19(月) 11:22:50.50 ID:???
>>941
EXISTS 使ってみては?
962NAME IS NULL:2011/09/19(月) 12:06:41.13 ID:???
>>957
それだとstart-endがすっぽりn-mに収まる時にひっかからない
963NAME IS NULL:2011/09/19(月) 13:50:04.79 ID:???
>>953
SELECT * FROM TBL
WHERE
n<m AND
(n BETWEEN start AND end
OR
m BETWEEN start AND end)
964NAME IS NULL:2011/09/19(月) 15:26:57.92 ID:eM/xKYwS
>>941
>>961
一般的にSQLの速度はEXISTS>IN=OR=UNION ALLなので
索引はEXISTSを検証してから考えてください
●oracleですまそ
SELECT 1 FROM DUAL
WHERE
EXISTS(
SELECT 1 FROM TBL AS A
WHERE カラムA=ワード)
AND
EXISTS(
SELECT 1 FROM TBL AS B
WHERE カラムB=ワード)
両方のEXISTSがTRUEならSELECT結果は1、それ以外ならスペース表示
MYSQLにDUAL表(1×1マスのDUMMY列を持つ表)なんてある?なかったらすまそ
965NAME IS NULL:2011/09/19(月) 15:30:06.35 ID:eM/xKYwS
↑ORやINからのEXISTS化はバグになりやすいから間違ってる結果を返すかもなので実験してください( ̄ω ̄)
966NAME IS NULL:2011/09/19(月) 15:32:12.20 ID:???
なんか違うだろ。
967NAME IS NULL:2011/09/19(月) 15:41:59.11 ID:eM/xKYwS
違った?重複チェックできると思うけど
968NAME IS NULL:2011/09/19(月) 15:48:10.64 ID:BzSFxFF/

テーブル A: フィールド t, r
テーブル B: フィールド p, t

テーブル B から p の値を指定して t の値を読み込みたいです。
これだけなら select t from B where p = hoge で済むと思います。

さらに条件を追加して、テーブルAにおいて t の値がそれに等しいようなレコードの数が最小なものを選ぶにはどのようにすればよいでしょうか?

例えば
テーブルAが (0, 1), (0, 2), (0, 3), (1, 1), (1, 2)
テーブルBが (0, 0), (0, 1), (1, 0), (1, 1), ...
となっていたら
(0), (1)
ではなく
(1)
だけを得たいです。
969968:2011/09/19(月) 15:50:16.34 ID:BzSFxFF/
なお、上記条件に合致する値はただ1つになるような実装となる予定です。これを用いることでコードが簡単になったり動作が速くなったりするならばそうしていただけるとありがたいです。
970NAME IS NULL:2011/09/19(月) 15:57:57.06 ID:eM/xKYwS
>>966
リトライします
971NAME IS NULL:2011/09/19(月) 16:02:16.07 ID:???
「ような」ってなんだよw
意味がよくわからんけど、たぶん、テンプレのどれかでできる。
972NAME IS NULL:2011/09/19(月) 16:09:55.18 ID:???
>>968
ごく一般的に書くとこうなる

select T3.t
from  (select t, count(*) as cnt from A group by t) as T1
    inner join
    (select min(cnt) as min_cnt from (select t, count(*) as cnt from A group by t)) as T2
    on T1.cnt = T2.min_cnt
    inner join
    B as T3
    on T1.t = T3.t
where  T3.p = hoge
;

limitとかrank()とか使えればもっと簡単になるけど
DBMS名を書いてもらわないと何とも
973NAME IS NULL:2011/09/19(月) 16:12:31.03 ID:???
それより誰か次スレ頼む
974NAME IS NULL:2011/09/19(月) 16:29:32.40 ID:eM/xKYwS
>>941
>>961
こんな感じ?
●oracleですまそ
SELECT 0 FROM DUAL
WHERE
EXISTS(
SELECT 1 FROM TBL AS A
WHERE カラムA=ワード
AND カラムB<>ワード
)
OR
EXISTS(
SELECT 1 FROM TBL AS B
WHERE カラムA<>ワード
AND カラムB=ワード)
片方のカラムに存在すればゼロを返却

オラクルでは<>つかうと索引使われなくなるどす
975NAME IS NULL:2011/09/19(月) 16:46:03.75 ID:???
>>972
T2にもhogeの条件必要だと思う
976968:2011/09/19(月) 17:29:04.72 ID:BzSFxFF/
>>972
ありがとうございます。
質問の文章が曖昧だったためで申し訳ないのですが、私の意図した質問と異なるものに答えられたように思います。

p が与えられたときに、
テーブルBに (p, t) というレコードが存在するような t の中で
テーブルAに存在する (t, r) というレコードの数が最小であるもの
を意図していました。

>>972 のコードは
p が与えられたときに、
テーブルBに (p, t) というレコードが存在するような t であって、
すべての t' に対して、
テーブルAに存在する (t, r) というレコードの数は テーブルAに存在する (t', r) というレコードの数 以下であるもの
を選択しているように思いますが、私の読み違いでしょうか?

DBMS というのが何を指すのかわからないのですが、MySQL の 4.1 以降の何か、でよいですか?
977NAME IS NULL:2011/09/19(月) 17:32:48.20 ID:???
お安い御用です。
978972:2011/09/19(月) 18:57:56.20 ID:???
ごめん間違えた

一般解はこんな感じかな?
select T3.t
from  (select T1.t,
         T1.cnt as cnt
     from  (select t, count(*) as cnt from A group by t) as T1
         inner join
         B as T2
         on T1.t = T2.t
     where  T2.p = hoge
    ) as T3
    inner join
    (select min(T4.cnt) as min_cnt
     from  (select    t, count(*) as cnt from A group by t) as T4
         inner join
         B as T5
         on T4.t = T5.t
     where  T5.p = hoge
    ) as T6
    on T3.cnt = T6.min_cnt
;

MySQL限定なら
select T1.t
from  (select t, count(*) as cnt from A group by t) as T1
    inner join
    B as T2
    on T1.t = T2.t
where  T2.p = hoge
order by T1.cnt
limit 1
;
979968:2011/09/19(月) 19:10:19.28 ID:BzSFxFF/
MySQL限定ってだけでそんな違うんですね! 昇順ソートして1つだけ取ればよいということでしょうか。とてもわかりやすくなりました。ありがとうございました。
980NAME IS NULL:2011/09/19(月) 19:50:45.46 ID:Hy6kQx4A
H2データベースを、MySQLに読み込んで、
MySQLから参照できるようにしたいのですが、
インポートはどのようにすればよいのでしょうか・・・
よろしくお願いします
981NAME IS NULL:2011/09/19(月) 19:51:14.84 ID:???
スレ違い。
982980:2011/09/19(月) 19:58:06.94 ID:???
>>981
すみません〜
誘導お願いできないでしょうか?
MySQLスレで質問させてもらったらいいでしょうか・・?
983NAME IS NULL:2011/09/19(月) 20:22:08.66 ID:???
>>982
MySQLの方でもどうかと思うがな〜
そのH2DBではテキスト(*.txt *.csv)で出力することは出来んの?
984NAME IS NULL:2011/09/19(月) 20:24:33.96 ID:???
>>953
おまえ、SQL以外でも人生でわからないことが多くて困ってるタイプだろ。
985980:2011/09/19(月) 20:41:07.14 ID:???
>>983
あぁ・・すみません
csvなどのテキスト出力方法がわからず困ってたのですが出力できました
このテキストをMySQLで読み込めばいいのですね。
ありがとうございました、助かりました
986NAME IS NULL
お安い御用です。