2015-07-29 13 views
5

Đây là một bài tập khá mới mẻ đối với tôi nhưng tôi cần phải tìm cách xác định các chuỗi mẫu trong một bảng. Vì vậy, ví dụ, cho phép nói rằng tôi có một bảng đơn giản tương tự như sau:Làm thế nào để bạn xác định chuỗi mẫu bản ghi trong các bản ghi bằng TSQL?

enter image description here

Bây giờ những gì tôi muốn làm là xác định và nhóm tất cả các hồ sơ đó có mô hình lập trình tự của các giá trị 5, 9 và 6 trình bày chúng trong một truy vấn. Bạn sẽ hoàn thành nhiệm vụ này bằng cách sử dụng T-SQL như thế nào?

Kết quả sẽ giống như thế này:

enter image description here

Tôi đã nhìn cho một số ví dụ về cách tiềm năng này có thể được thực hiện nhưng không thể tìm thấy bất cứ điều gì đó thực sự giúp.

+0

Bạn có thể thêm một đoạn văn bản nhỏ về mẫu đó - nó có thể lớn đến mức nào không? –

+0

Vì vậy, bạn sẽ có một mẫu được cung cấp như 'declare @Pattern dưới dạng bảng (Seq Int, Val Int); chèn vào các giá trị @Pattern (Seq, Val) (1, 5), (2, 9), (3, 6); '? Có vẻ như tham gia với một số đối sánh, nhóm và số lượng Row_Number ưa thích.Một biến thể kỳ lạ "khoảng trống và đảo" vấn đề tại thời điểm đó. – HABO

+0

@BogdanBogdanov Mẫu sẽ không bao giờ có nhiều hơn 3 số liên tiếp. Trong trường hợp này là 5,9 và 6. Nhưng lý tưởng, giải pháp sẽ có thể chứa một chuỗi lớn hơn nếu cần thiết với một số sửa đổi. Giá trị là số nguyên. Hy vọng rằng, tôi đã giải thích câu hỏi của bạn đúng cách. Nếu không, vui lòng cho tôi biết – Mark

Trả lời

7

Bạn có thể sử dụng các truy vấn sau đây được bao bọc trong một CTE để gán số thứ tự với các giá trị chứa trong chuỗi của bạn:

;WITH Seq AS (
    SELECT v, ROW_NUMBER() OVER(ORDER BY k) AS rn 
    FROM (VALUES(1, 5), (2, 9), (3, 6)) x(k,v) 
) 

Output:

v rn 
------- 
5 1 
9 2 
6 3 

Sử dụng trên CTE bạn có thể xác định các hòn đảo, tức là các lát của các hàng tuần tự có chứa toàn bộ chuỗi:

;WITH Seq AS (
    SELECT v, ROW_NUMBER() OVER(ORDER BY k) AS rn 
    FROM (VALUES(1, 5), (2, 9), (3, 6)) x(k,v) 
), Grp AS (
SELECT [Key], [Value], 
     ROW_NUMBER() OVER (ORDER BY [Key]) - rn AS grp    
FROM mytable AS m 
LEFT JOIN Seq AS s ON m.Value = s.v 
) 
SELECT * 
FROM Grp 

Output:

Key Value grp 
    ----------------- 
    1 5  0 
    2 9  0 
    3 6  0 
    6 5  3 
    7 9  3 
    8 6  3 

grp lĩnh vực giúp bạn xác định chính xác những hòn đảo này.

Tất cả bạn cần làm bây giờ là chỉ lọc ra nhóm phần:

;WITH Seq AS (
    SELECT v, ROW_NUMBER() OVER(ORDER BY k) AS rn 
    FROM (VALUES(1, 5), (2, 9), (3, 6)) x(k,v) 
), Grp AS (
SELECT [Key], [Value], 
     ROW_NUMBER() OVER (ORDER BY [Key]) - rn AS grp    
FROM mytable AS m 
LEFT JOIN Seq AS s ON m.Value = s.v 
) 
SELECT g1.[Key], g1.[Value] 
FROM Grp AS g1 
INNER JOIN (
    SELECT grp 
    FROM Grp 
    GROUP BY grp 
    HAVING COUNT(*) = 3) AS g2 
ON g1.grp = g2.grp 

Demo here

Lưu ý: Phiên bản ban đầu của câu trả lời này đã sử dụng một INNER JOIN để Seq. Điều này sẽ không hoạt động nếu bảng chứa các giá trị như 5, 42, 9, 6, dưới dạng 42 sẽ được lọc theo INNER JOIN và chuỗi này được xác định sai là giá trị hợp lệ. Tín dụng chuyển đến @HABO cho chỉnh sửa này.

+0

Sẽ không 'đầu tiên bên trong 'của bạn thả bất kỳ' mytable' giá trị mà không phù hợp với mô hình ở tất cả, có hiệu quả bỏ qua các giá trị chưa từng có hơn là không phù hợp với mô hình? – HABO

+0

@HABO Có, 'INNER JOIN' đầu tiên thực hiện chính xác điều đó, tức là nó lọc ra bất kỳ giá trị chưa khớp nào, như' 8', '3'. –

+1

Nếu bạn sử dụng 'LEFT OUTER JOIN' để' Seq' khi tạo thành 'Grp' thì bạn sẽ có thêm hàng trong một hòn đảo nếu, ví dụ' mytable' chứa 5, 42, 9, 6. Kiểm tra cuối cùng của ' COUNT' sẽ tung ra nhóm đó là chưa từng có. – HABO

1

Không rất tối ưu, nhưng tôi nghĩ rằng câu trả lời propper:

CREATE TABLE pattern (
    rowID INT IDENTITY(1,1) PRIMARY KEY, 
    rowValue INT NOT NULL 
); 

INSERT INTO pattern (rowValue) VALUES (5); 
INSERT INTO pattern (rowValue) VALUES (9); 
INSERT INTO pattern (rowValue) VALUES (6); 

SELECT * FROM pattern; 

SELECT Trg.* FROM Keys Trg 
INNER JOIN pattern Pt ON (Trg.fValue = Pt.rowValue) 
INNER JOIN (
    SELECT K.fKey - P.rowID AS X, COUNT(*) AS Xc FROM Keys K 
     LEFT JOIN pattern P ON (K.fValue = P.rowValue) 
    WHERE 
     (P.rowID IS NOT NULL) 
    GROUP BY K.fKey - P.rowID 
    HAVING COUNT(*) = (SELECT COUNT(*) FROM pattern) 
) Z ON (Trg.fKey - Pt.rowID = Z.X); 

tôi sử dụng một bảng cho mô hình gia nhập nó vào bảng chính. Tôi tính chênh lệch giữa Key và mẫu Key và tôi chỉ hiển thị các hàng có sự khác biệt phù hợp (và các hàng đếm cho các hàng phù hợp khác biệt bên trong bảng mẫu).

+0

Tôi sẽ lựa chọn câu trả lời thứ nhất, tôi tin rằng câu trả lời thứ 2 có thể là một giải pháp rất hợp lý nhưng về phương diện rất đơn giản và thanh lịch (đặc biệt là đối với tôi) Tôi đang tìm kiếm. Bogdan, tôi sẽ cho bạn một lá phiếu cho tính hữu ích của câu trả lời của bạn. Cảm ơn! – Mark

+0

10x @Mark. Tôi đồng ý với bạn rằng câu trả lời 1 là tốt hơn nhiều (tôi đã bình chọn nó :)). –

Các vấn đề liên quan