【帰ってきた】SQL質疑応答スレ 4問目

このエントリーをはてなブックマークに追加
952NAME IS NULL:2007/10/23(火) 17:32:55 ID:???
>>950
ここはSQLServerのスレじゃないよ

Microsoft SQL Server 総合スレ 5
http://pc11.2ch.net/test/read.cgi/db/1175091880/
953NAME IS NULL:2007/10/23(火) 17:38:53 ID:???
>>951
共有ロック式の場合のRepeatable Readは、トランザクションが読み取ったレコード全部に
コミットまでの期間共有ロックをかけてゆくと考えればいい。
>トランザクションBが表AのレコードBをUpdate更新して、コミット
この前にトランザクションAがレコードAを読み取っていればトランザクションBの更新はロックされ待機状態になる。
この前にトランザクションAがレコードAを読み取っていなければ競合は起きない。

マルチバージョニングの場合はシリアライザブルと同じ動作になる実装が多いと思う。Oracleとか。
954NAME IS NULL:2007/10/23(火) 17:39:23 ID:4X2HVnn9
>952
失礼しました。 そちらに質問しました。
955NAME IS NULL:2007/10/23(火) 19:24:45 ID:???
なるほど。あなたは天才ですね。まぁ、言葉の定義の問題になっちゃうかも
しれまんせが、Repetable ReadはOracleとかのシリアラザブルのような動作が本来あるべき意味かなと
思いまして。よく、Repetable Readの説明で*実際にSELECT*文を同じ条件などで
検索させる説明がありますが、あくまで例で、本来はSELECT文を発行するかは関係なく、
Repeatable Readのトランザクションの*開始時点*の既に存在する行のみ
保証し、開始以降他によって追加された行(ファントム行)は保証しないのが、本来のRRなのかなと。
つまり、951の例では、トランザクショクンAの更新で、既にBによって更新され、
トランザクションの開始時点の行を保証できないから、エラーで落とす。
956NAME IS NULL:2007/10/23(火) 19:25:52 ID:???
それであれば、よく、Read Committedレベルの時に、日付のタイムスタンプ見てロスト
アップデート防いだりしますが、RRだと本来は共有ロックとか実装方式に関係なく、
ロストアップデートとか考える必要がない。

と、共有ロック方式のRRは偽RRじゃないかなと。まぁ、すっきりしました。
ありがとうございます。
957NAME IS NULL:2007/10/23(火) 20:27:42 ID:???
>>955
いや、ちょっと理解が違うような。

Repeatable Read と Serializable では、
あるトランザクションが一度読んだレコードが変更されないのはどちらも同じ。
(Read Committed では変更されることがありうる。
 そういう意味で>>956の理解は正しい。)

Repeatable Read と Serializable の違いは、
Repeatable Read ではあるトランザクションが最初にある条件で検索し、
後でもう一度同じ条件で検索したとき、レコードが増えていることが
ありうるのに対して、Serializable ではそれも許さない。
958NAME IS NULL:2007/10/23(火) 21:03:12 ID:???
>>957
あ、すみません。語弊がありました。
>Repetable ReadはOracleとかのシリアラザブルのような動作が本来あるべき意味
はOracleのシリアライザブルみたいに、シリアライズ不可能ですみたいな感じに951の
例で、「トランザクションAが同じ表AのレコードBをUpdateで更新 」の時に、
リピータブル不可能ですとエラーで落とすべきという意味です。おっしゃるとおり、Serializableはファント行も許さない、
つまり、トランザクション開始時のデータの完璧なスナップショットを保証することと思ってます。

ただ、共有ロック式のRRはトランザクション開始時に既に存在していた行を保証するのではなく、
開始後、SELECTして一度読んだ行だけしか保証しないので、こういうトランザクションの
振る舞いをRRって言わない方がいいのかなと思ってただけです。まぁ、言葉の問題ですが。えらい混乱しました。

959仕様書無しさん:2007/10/23(火) 21:41:35 ID:XcO2seYm
みなさんはSEなのかPGなのでしょうけど
具体的なビジョンはもってますか?
960NAME IS NULL:2007/10/23(火) 21:49:13 ID:???
>>958
951の例で言えば「トランザクションAが同じ表AのレコードBをUpdateで更新」は
Repeatable ReadでもSerializableでも許される。
(トランザクションBが更新する前にトランザクションAが読んでいなければ。)

つまり、問題は開始時点でどうたったかじゃなくて一度読んだかどうか。

その上で、Repeatable Readでは一度読んだ「レコード」に対してだけ
ロックがかかるのに対して、Serializableでは一度検索した「条件」に対しても
ロックがかかるというイメージ。
Serializableでは他のトランザクションが一度検索した条件に抵触するレコードは
更新できない。

ただ、この違いを実装しているDBMSがあるかどうかは知らない。
961NAME IS NULL:2007/10/23(火) 22:36:24 ID:BuF9yVzC
教えてください
列1,列2
A, AA
A, AB
B, BA
B, BB
B, BC
とある時に、列1でグルーピングされたROWNUMのような値を
得るにはどうしたらよいでしょうか?
つまり、このような結果が欲しいです。

列1,列2,欲しい値
A, AA, 1
A, AB, 2
B, BA, 1
B, BB, 2
B, BC, 3

DBはOracle10gです。
>>881と似ている気がするのですが、もう少しシンプルです。
962NAME IS NULL:2007/10/23(火) 22:47:31 ID:???
select 列1,列2, rank() over (partition by 列1 order by 列2) as ,欲しい値 
from xxxx order by 列1,列2
963NAME IS NULL:2007/10/23(火) 23:49:44 ID:BuF9yVzC
>>962
ありがとうございます。なるほど。

ついでに言うと、このような取り方もできますか?
列1,列2,欲しい値
A, AA, 1, 1
A, AB, 1, 2
B, BA, 2, 1
B, BB, 2, 2
B, BC, 2, 3

教えてもらった方法を参考に考えたのですが、
SELECT 列1, ROW_NUMBER() OVER(ORDER BY 列1)
GROUP BY 列1
の結果と、>>962で教えていただいた結果をJOINしようと思ったのですが、
もっと華麗な方法がありますか?
と、教えていただいた検索結果を結合しようと思ったのですが、
964NAME IS NULL:2007/10/24(水) 01:18:07 ID:???
あるテーブルに以下のデータが入ってるとします。
(テストの点数と氏名が入ってるテーブルです))

---------------------
name, tokuten
---------------------
satou, 60
nakata, 70
takahasi, 80
hukuda, 90
nakamura, 100

このテーブルからSQLで、以下の結果を導き出したいです。
---------------------
name, tokuten
---------------------
nakamura, 100
hukuda, 90
takahasi, 80
その他, 65
---------------------

上位三名のnameとtokutenを表示し、
四位以降は、"その他"でまとめて平均値をだします。
このようにするSQLはどのように書けばよろしいでしょうか?

MySQLを使っております。
よろしくお願い致します。
965NAME IS NULL:2007/10/24(水) 01:28:26 ID:???
cursor cur is
select * from A
union all
select * from B
for update

て書くとforうp句は書けネーヨって怒られるんだけど、もしかして ROWID を
セレクツするようにして、where current of cur って書いてるところを
where rowid = rec.rowid って書くと超いい感じじゃね?
やべ、スゲー発見しちゃったかも。
966NAME IS NULL:2007/10/24(水) 02:35:55 ID:???
>>964
SELECT CASE WHEN cnt=4 THEN 'その他' ELSE name END AS name,tokuten FROM (
  SELECT cnt , avg(tokuten) AS tokuten FROM (
   SELECT (SELECT CASE WHEN count(*)+1 < 4 THEN count(*)+1 ELSE 4 END FROM Table WHERE tokuten > T1.tokuten)AS cnt ,* FROM Table AS T1
  )AS T2 GROUP BY cnt
) AS T3 LEFT JOIN Table USING(tokuten) ORDER BY tokuten DESC;
967966:2007/10/24(水) 02:38:29 ID:???
見落としてた。
MySQLで動くかどうかは知らない。
968NAME IS NULL:2007/10/24(水) 04:50:05 ID:???
>>963
DENSE_RANK OVER(ORDER BY 列1)
969963:2007/10/24(水) 09:18:09 ID:qq2N0MNt
>>968
DENSE_RANK!!
列1の順位を同じ順位を飛ばさないように付与すればいいのか!思いつきませんでした。
結合しなくて済んで、すごくシンプルになりました。
ありがとうございます。

SELECT 列1,列2,
DENSE_RANK OVER(ORDER BY 列1) as G1
RANK() OVER (PARTITION BY 列1 ORDER BY 列2) as G2
FROM XXX ORDER BY 列1,列2
970NAME IS NULL:2007/10/24(水) 23:27:14 ID:j/8QV/sQ
テーブル名 d_tbl

YMD
20101010
20091010
20080808
20071010
20070928
20070303
20061220
20061014
20060907

上のようなデータが入ったテーブルから
2006年の10月だけを取り出すにはどうしたらいいのでしょう。
よろしくお願いします。
971NAME IS NULL:2007/10/25(木) 00:01:12 ID:???
>>970
select YMD from d_tbl where YMD like '200610*';
972NAME IS NULL:2007/10/25(木) 00:48:03 ID:???
>>971
%じゃね?
973970:2007/10/25(木) 08:05:06 ID:???
>>971
すみません間違いました。
何年かは関係なく、10月を取り出す場合はどうしたらいいのでしょうか。
974NAME IS NULL:2007/10/25(木) 08:42:15 ID:???
YMD like '____10%'
975NAME IS NULL:2007/10/25(木) 09:13:21 ID:???
substring(YMD, 5, 2) = '10'
976970:2007/10/25(木) 09:52:24 ID:arcZFewB
>>974-975
SUBSTRの場合も教えて頂き、ありがとうございます。
977NAME IS NULL:2007/10/25(木) 11:24:39 ID:???
どちらも9999年までしか使えないなw
978NAME IS NULL:2007/10/25(木) 11:46:39 ID:???
YMD like '%10__'
979NAME IS NULL:2007/10/26(金) 02:03:40 ID:EigH0966
すみません、SQLの第一、二、三正規系などが初心者向けに
解説されているサイトはないでしょうか?
意味がわからなく困っています・・・・参考書四でもさぱーりです。。。
因みに、やさしく学ぶ1SQLです
980NAME IS NULL:2007/10/26(金) 03:44:54 ID:???
つデータベースの教科書
981NAME IS NULL:2007/10/26(金) 07:12:20 ID:???
>>980
うざい
982NAME IS NULL:2007/10/26(金) 17:18:23 ID:BxaZnJ00
すいません。SQLを教えてください。

ID int
TYPE int
DATE datetime
からなるテーブルがありまして、以下のようにデータが入ってます。
| id | type | date |
| 1 | 1 | 2007-10-26 08:00:00 |
| 2 | 1 | 2007-10-26 09:00:00 |
| 3 | 1 | 2007-10-26 10:00:00 |
| 4 | 2 | 2007-10-26 11:00:00 |
| 5 | 2 | 2007-10-26 12:00:00 |
| 6 | 2 | 2007-10-26 13:00:00 |
| 7 | 3 | 2007-10-26 14:00:00 |
| 8 | 3 | 2007-10-26 15:00:00 |
| 9 | 3 | 2007-10-26 16:00:00 |

これをTYPE別にdateが最新の一件ずつで取りたいのですが、
どのようにしたら良いでしょうか?

上記の例の場合
| 3 | 1 | 2007-10-26 10:00:00 |
| 6 | 2 | 2007-10-26 13:00:00 |
| 9 | 3 | 2007-10-26 16:00:00 |
を取りたいと思います。

お手数おかけしますがご教授の程よろしくお願いします。
983NAME IS NULL:2007/10/26(金) 17:57:26 ID:???
typeをgroup化してdateでmaxを取る
984NAME IS NULL:2007/10/26(金) 19:55:11 ID:BxaZnJ00
>>983
レスありがとうございます。

select type,max(date) from table group by type;
これでtype別のdateは取れますが、
idが欲しい場合はどうしたらよいでしょうか?

select id,type,date
from table
where date in (
select max(date) date from table group by type
);
これだとダメですよね。
985NAME IS NULL:2007/10/26(金) 21:42:09 ID:???
>>984
ポカーン
>>980
986NAME IS NULL:2007/10/26(金) 22:18:04 ID:4m4QhRkA
すみません、質問させてください
aの重複値を無視して下のようにカウントしたいのですが
どのように書いたら良いのでしょうか?
ご教示お願いします

a b
------
1 1999
2 1999
3 2000
3 2000
4 2001
5 2001
5 2001

b  count(*)
--------
1999 2
2000 1
2001 2
987NAME IS NULL:2007/10/26(金) 22:21:41 ID:???
count(*) by b
988NAME IS NULL:2007/10/26(金) 22:22:25 ID:???
間違えたgroup by b
989NAME IS NULL:2007/10/26(金) 22:26:01 ID:???
>>986
SELECT b,count(*) FROM (SELECT a,b FROM Table GROUP BY a,b) AS T1 GROUP BY b;
990NAME IS NULL:2007/10/26(金) 22:35:37 ID:???
select b, count(*) from (select distinct a, b from Table) group by b;
991NAME IS NULL:2007/10/26(金) 22:48:40 ID:???
皆様ありがとうございます

>>988
その方法だと重複がカウントされてしまいました

>>989>>990
今MySQL 5.0.45で実験してるんですが、サブクエリが何故かエラーになってしまいました
ちょっと環境について調べてきます
992986:2007/10/26(金) 22:54:25 ID:???
すみません、完璧でしたテーブル名をタイポしてました
皆様ありがとうございます

サブクエリは必須みたいですね、勉強になりました
993NAME IS NULL:2007/10/27(土) 21:10:02 ID:???
994NAME IS NULL:2007/10/28(日) 22:51:58 ID:???
>>993

こっち埋めるか
995NAME IS NULL:2007/10/28(日) 22:53:24 ID:???
埋め
996NAME IS NULL:2007/10/28(日) 22:55:02 ID:???
ume
997NAME IS NULL:2007/10/28(日) 22:55:14 ID:???
998NAME IS NULL:2007/10/28(日) 22:57:37 ID:???
998
999NAME IS NULL:2007/10/28(日) 22:57:53 ID:???
1000
1000NAME IS NULL:2007/10/28(日) 22:58:25 ID:???
10011001
このスレッドは1000を超えました。
もう書けないので、新しいスレッドを立ててくださいです。。。