2011-11-15 8 views
15

私が複製したい動作は、-A-Bフラグを持つgrepのようなものです。 例えばgrep -A 2 -B 2 "hello" myfile.txtは、 "hello"を持つすべての行を表示しますが、2行前と2行後にも表示されます。条件に一致する行の前後にN行を選択しますか?

+--------+-------------------------+ 
| id  | message    | 
+--------+-------------------------+ 
| 1  | One tow three   | 
| 2  | No error in this  | 
| 3  | My testing message  | 
| 4  | php module test   | 
| 5  | hello world    | 
| 6  | team spirit    | 
| 7  | puzzle game    | 
| 8  | social game    | 
| 9  | stackoverflow   | 
|10  | stackexchange   | 
+------------+---------------------+ 

今のようなクエリ: Select * from theTable where message like '%hello%'はになります:私は前にN行を選択し、別のパラメータ "N" を置くことができますどのように

5 | hello world

、および は、このテーブルのスキーマとさせて頂きます一致するレコードの後のN行、つまりN = 2の場合、結果は次のようになります。

| 3  | My testing message  | 
    | 4  | php module test   | 
    | 5  | hello world    | 
    | 6  | team spirit    | 
    | 7  | puzzle game    | 
  • わかりやすくするために 'like%TERM%'は1行だけに一致します。
  • ここで結果は自動インクリメントidフィールドでソートされています。
+0

少なくとも –

+0

..順序を指定yi_Hやあ、その質問 – DhruvPathak

+0

に最後のポイントとして指定された最初のステートメント/クエリは、常に1行のみを戻すだろうか?または複数の行を返すことはできますか? –

答えて

11

右を試してみてください、これがすべてで有効なMySQLのであれば知っているが、どの程度

SELECT t.* 
FROM theTable t 
     INNER JOIN (
      SELECT id FROM theTable where message like '%hello%' 
     ) id ON id.id <= t.id 
ORDER BY 
     ID DESC 
LIMIT 3      
UNION ALL 
SELECT t.* 
FROM theTable t 
     INNER JOIN (
      SELECT id FROM theTable where message like '%hello%' 
     ) id ON id.id > t.id 
ORDER BY 
     ID 
LIMIT 2 
+8

idの間にギャップがある場合、これは機能しない可能性があります。 –

+0

IDが増分であると仮定すると、これは部分的に機能します。正しいID値を返しません。http://sqlize.com/i3UzLmm9u8 – mellamokb

+0

これでは、N個の制限を持つ2つの余分な結合が必要になります。鉱山は実際にはギャップがないと仮定しています –

6

これが私の作品、

Select * from theTable 
Where id >= 
(Select id - variableHere from theTable where message like '%hello%') 
Order by id 
Limit (variableHere * 2) + 1 
+0

これは 'id ON t.id id.id'(エイリアスは 'id'と呼ばれるので、それ以外の場合は' t.id'を自分と比較します)、それは動作します:http://sqlize.com/fIR8gPZ1CO – mellamokb

+0

@mellamokb - ありがとうございました。私はエラーを修正しました –

2

ないでください:

SELECT child.* 
FROM stack as child, 
(SELECT idstack FROM stack WHERE message LIKE '%hello%') as parent 
WHERE child.idstack BETWEEN parent.idstack-2 AND parent.idstack+2; 
+0

[limit句で変数を使う](http://bugs.mysql.com/bug.php?id=11918):http: //sqlize.com/3Q9z45906z – mellamokb

+0

MySqlが変数を許可できるかどうか分かりませんが、単に変数variableをゆるやかに使用します。そうでない場合は、中間層言語のデータアクセスライブラリのパラメータ化されたクエリを使用して、それはあなたの変数をそこに渡します。もしあなたが言語でクエリを実行しているならば、連結を使用しないでください。 –

+0

制限変数はその言語ですが、mysqlは問題ありません。 例: '$ limit = 10; $ query =" temp LIMIT $ limitからのIDの選択 "; ' –

5

てみてくださいこの単純なもの(編集) -

CREATE TABLE messages(
    id INT(11) DEFAULT NULL, 
    message VARCHAR(255) DEFAULT NULL 
); 

INSERT INTO messages VALUES 
    (1, 'One tow three'), 
    (2, 'No error in this'), 
    (3, 'My testing message'), 
    (4, 'php module test'), 
    (5, 'hello world'), 
    (6, 'team spirit'), 
    (7, 'puzzle game'), 
    (8, 'social game'), 
    (9, 'stackoverflow'), 
    (10, 'stackexchange'); 

SET @text = 'hello world'; 

SELECT id, message FROM (
    SELECT m.*, @n1:[email protected] + 1 num, @n2:=IF(message = @text, @n1, @n2) pos 
    FROM messages m, (SELECT @n1:=0, @n2:=0) n ORDER BY m.id 
) t 
WHERE @n2 >= num - 2 AND @n2 <= num + 2; 

+------+--------------------+ 
| id | message   | 
+------+--------------------+ 
| 3 | My testing message | 
| 4 | php module test | 
| 5 | hello world  | 
| 6 | team spirit  | 
| 7 | puzzle game  | 
+------+--------------------+ 

N値はユーザー変数として指定できます。現在は「2」です。

このクエリは行番号で機能し、最も近いレコードが返されることを保証します。

+0

こんにちは、私は信じていますこれは私が探しているものですが、@ n2の機能についてはまだ分かりません。もっと説明できますか? num列は右の行番号ですか? pos列は何ですか? – dieend

+0

@ n2は変数ですが、IF制御関数はフィールド 'message'が@textに等しいときに値@ n1を設定します。それ以外の場合は何もしません。 – Devart

+0

私はそれを試しているとき、:n2は、フィールドメッセージが:textに等しい行の前にあるすべての行について0に設定されます。したがって、WHEREは行with:textの前に行を取得するためには正しく機能しません。 たとえば、4行目に:textという行があります。 :1〜3行目のn2は0になります。 pos> = num-2 - > 0> = 3-2はfalseであるため、行3は前の行として選択されませんが、実際には4行目の前の行です。 QMIIW – dieend

1

(MS SQL Serverの場合のみ)

最も信頼できる方法は、ID内にギャップがある場合、それは問題ではない方法でROW_NUMBER関数を使用することです。これは、検索結果が複数出現し、それぞれの結果の上下2つを適切に返す場合にも機能します。

WITH 

srt AS (
    SELECT ROW_NUMBER() OVER (ORDER BY id) AS int_row, [id] 
    FROM theTable 
), 

result AS (
    SELECT int_row - 2 AS int_bottom, int_row + 2 AS int_top 
    FROM theTable 
     INNER JOIN srt 
      ON theTable.id = srt.id 
    WHERE ([message] like '%hello%') 
) 

SELECT theTable.[id], theTable.[message] 
FROM theTable 
    INNER JOIN srt 
     ON theTable.id = srt.id 
    INNER JOIN result 
     ON srt.int_row >= result.int_bottom 
     AND srt.int_row <= result.int_top 
ORDER BY srt.int_row 
+0

あなたの質問にmysqlというタグが付いていることが判明しました。このメソッドは、SQL Server用です。ごめんなさい。 – David

0

IDの代わりに日付を使用して回答を追加する。 ここでのユースケースは、1レコードがpr週のオンコールローテーションテーブルです。 編集のために、意図した目的のためにIDが無効である可能性があります。 いくつかのレコードが週、日付またはその他のコースを持つユースケースは、もちろん修正する必要があります。

+----------+--------------+------+-----+---------+----------------+ 
| Field | Type   | Null | Key | Default | Extra   | 
+----------+--------------+------+-----+---------+----------------+ 
| id  | int(11)  | NO | PRI | NULL | auto_increment | 
| startdate| datetime  | NO |  | NULL |    | 
| person | int(11)  | YES | MUL | NULL |    | 
+----------+--------------+------+-----+---------+----------------+ 

クエリ:

SELECT child.* 
FROM rota-table as child, 
(SELECT startdate 
    FROM rota-table 
    WHERE YEARWEEK(startdate, 3) = YEARWEEK(now(), 3)) as parent 
WHERE 
    YEARWEEK(child.startdate, 3) >= YEARWEEK(NOW() - INTERVAL 25 WEEK, 3) 
    AND YEARWEEK(child.startdate, 3) <= YEARWEEK(NOW() + INTERVAL 25 WEEK, 3) 
関連する問題