SQLServerネタ:m行目からn件取得するSQL
チャレンジしましたよ。えぇ。
下記のテーブルを作成。 if exists ( select * from dbo.sysobjects where id = object_id(N'[dbo].[T_RowN_CountM]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table [dbo].[T_RowN_CountM] GO CREATE TABLE [dbo].[T_RowN_CountM] ( [IDKey] [int] NOT NULL , [Name] [varchar] (8000) COLLATE Japanese_BIN NULL , CONSTRAINT [PK_T_RowN_CountM] PRIMARY KEY CLUSTERED ( [IDKey] ) ON [PRIMARY] ) ON [PRIMARY] GO INSERT T_RowN_CountM VALUES(6,'a') INSERT T_RowN_CountM VALUES(7,'b') INSERT T_RowN_CountM VALUES(8,'c') INSERT T_RowN_CountM VALUES(11,'d') INSERT T_RowN_CountM VALUES(12,'e') INSERT T_RowN_CountM VALUES(14,'f') INSERT T_RowN_CountM VALUES(15,'g') INSERT T_RowN_CountM VALUES(16,'h') INSERT T_RowN_CountM VALUES(17,'i') GO まず最初に考えたのが 「m行目から」→「上からm番目以降のレコード取得」の部分 SQLServerにはRecordIDや物理Noなんてないから、 昇順なキーがあるものを前提としてSQL発行による 取得を行う。 さてSQL解釈的にやろうとすることを分解すると 1.TOPの指定=n 2.1の中で最大値をもつIDを取る。 3.2を持つレコードがそれ。 になると思うのでまずは1から。 具体的に2行目から3件取得を例にやってみる。 [SQL] SELECT TOP 2 IDKey FROM T_RowN_CountM [Result] 6 7 これで1はOK。 次に2。 [SQL] SELECT MAX(IDKey) FROM ( SELECT TOP 2 IDKey FROM T_RowN_CountM ) AS V_Row すると... [Result] 17 ( ゜Д゜)ハァ?なんでじゃ?と試行錯誤。実はORDERが必要だと いう結論に達した(ナゼかは知らぬ)。 >推測だが、TOPは「取得した部分の一部を返す」という性質 >から実はWHERE句がないと全件取得していると思われる。 >その内の最大なのだから...?にしてもORDERとの結びが... >あーやっぱわからんわぁ。 あとは3でのINNER JOINにより出来たのがρ(・д・*)コレ [SQL] SELECT * FROM T_RowN_CountM INNER JOIN ( SELECT MAX(IDKey) AS RowN FROM ( SELECT TOP 2 IDKey FROM T_RowN_CountM ORDER BY IDKey ) AS V_Row ) AS V_RowN ON T_RowN_CountM.IDKey = V_RowN.RowN [Result] 7 b 7 うし。次に、m件の方か。そのまんまTOPになるんじゃねーの? nのIDKey以上かつTOP mでどう? [2行目から3件とる場合] SELECT TOP 3 * FROM T_RowN_CountM INNER JOIN ( SELECT MAX(IDKey) AS RowN FROM ( SELECT TOP 2 IDKey FROM T_RowN_CountM ORDER BY IDKey ) AS V_Row ) AS V_RowN ON T_RowN_CountM.IDKey >= V_RowN.RowN ORDER BY IDKey 暇つぶし?に応用してみた。 ランダムにnレコード目を取得するのがρ(・д・*)コレ DECLARE @vchCrLf AS VARCHAR(2) DECLARE @intCount AS INT DECLARE @vchSQL AS VARCHAR(8000) SET @vchCrLf = CHAR(13) + CHAR(10) SELECT @intCount = COUNT(*) FROM T_RowN_CountM SET @vchSQL = 'SELECT TOP 1 * ' + @vchCrLf + 'FROM T_RowN_CountM' + @vchCrLf + 'INNER JOIN ( SELECT MAX(IDKey) AS RowN' + @vchCrLf + ' FROM ( SELECT TOP ' + CAST(FLOOR(RAND() * @intCount) + 1 AS VARCHAR(100)) + ' IDKey' + @vchCrLf + ' FROM T_RowN_CountM' + @vchCrLf + ' ORDER BY IDKey' + @vchCrLf + ' ) AS V_Row' + @vchCrLf + ' ) AS V_RowN' + @vchCrLf + ' ON T_RowN_CountM.IDKey >= V_RowN.RowN' + @vchCrLf EXEC (@vchSQL) PRINT @vchSQL これをベースに ・サイコロ ・ジャンケン ・今日の占い ・明日の天気 Σ(゜д゜)オイオイ などに応用できるのでは...