2011-10-04 70 views
1

我在SQL Server表(已排序)有以下幾點:如何編寫檢查前一行的SQL查詢?

stringname 
========== 
stringA 
stringA 
stringB 
stringB 
stringA 
stringC 
stringC 
stringC 
stringA 

我想輸出如下:

stringname previous_stringname count 
========== =================== ===== 
stringA NULL    1 
stringA stringA    1 
stringA stringB    1 
stringA stringC    1 
stringB stringA    1 
stringB stringB    1 
stringC stringA    1 
stringC stringC    2 

也就是說,在原始表和每個字符串名稱每個stringname的前一個條目,我想輸出它的每個前一個字符串的次數(第一個條目爲NULL)。

我將如何爲此編寫SQL查詢?

我使用SQL Server 2008的

+0

我不確定您能否在SQL中輕鬆完成此操作。你最好查詢數據並讓程序處理邏輯。 –

+0

期待ROW_NUMBER()和自加入 –

+0

ROW_NUMBER不會幫助,因爲您無法按順序使用常量。您需要在表中添加另一個標識符,例如'IDENTITY'列,以確保按您希望的順序查詢字符串名稱。 – Wil

回答

2

遞歸是沒有必要的;只是使用:

select b.stringname as stringname, a.stringname as previous_stringname 
    into #tmp 
    from (select stringname, row_number() over (order by id /* $/0 */) as row from testing) a 
    right outer join (select stringname, row_number() over (order by id /* $/0 */) as row from testing) b 
    on a.row = b.row - 1; 
select *, count(*) as [count] from #tmp group by stringname, previous_stringname; 
1

的folllowing會做的伎倆,但換來的答案我想你谷歌「遞歸」,看看谷歌建議搜索:)

澄清:遞歸通過加入行 - 1到臨時表和CTE之間的行而發生。此方法取決於具有獨立的IDENTITY列(在此情況下爲ID),並使用ROWNUMBER()來解決ID中可能存在的任何空白。由於ROW_NUMBER()不能用於JOIN我不得不求助於在CTE的遞歸部分使用子查詢。即使你知道你有連續的ID,但我仍建議使用ROW_NUMBER來進行這種查詢,只是爲了安全起見,因爲間隙會讓它變得混亂起來。

CREATE TABLE #tmp (id INT IDENTITY(1,1),stringname NVARCHAR(MAX)) 

INSERT #tmp (stringname) 

VALUES 
('stringA') 
,('stringA') 
,('stringB') 
,('stringB') 
,('stringA') 
,('stringC') 
,('stringC') 
,('stringC') 
,('stringA') 

;WITH StringNames 
AS(
SELECT 
    ROW_NUMBER() OVER (ORDER BY ID) AS Row --Accounts for gaps in ID 
    ,stringname 
    ,CAST(NULL AS NVARCHAR(MAX)) AS previous_stringname  
FROM #tmp 
WHERE id = 1 
UNION ALL 
SELECT t.Row 
    ,t.stringname 
    ,s.stringname AS previous_stringname 
    FROM (
      SELECT 
      ROW_NUMBER() OVER (ORDER BY ID) AS Row --Accounts for gaps in ID 
      ,stringname 
      FROM #tmp) AS t 
JOIN StringNames AS s ON t.row - 1 = s.row 
) 

SELECT 
    DISTINCT 
    stringname 
    ,previous_stringname 
    ,COUNT(*) AS count 
FROM StringNames 
GROUP BY 
    stringname 
    ,previous_stringname 
ORDER BY stringname 
0

@Wil,你爲什麼需要標識列?

數據

CREATE TABLE #table (stringname NVARCHAR(MAX)) 

INSERT #table (stringname) 
VALUES ('stringA') 
     ,('stringA') 
     ,('stringB') 
     ,('stringB') 
     ,('stringA') 
     ,('stringC') 
     ,('stringC') 
     ,('stringC') 
     ,('stringA') 

查詢

;WITH [cteRowNumbers] AS (
    SELECT ROW_NUMBER() OVER (ORDER BY $/0) AS [RowNumber], 
      [stringname], 
      CAST(NULL AS NVARCHAR(MAX)) AS [previous_stringname] 
    FROM #table 
) 
,[cteStringNames] AS (
    SELECT [RowNumber], 
      [stringname], 
      [previous_stringname] 
    FROM (
     SELECT TOP 1 
       [RowNumber], 
       [stringname], 
       [previous_stringname] 
     FROM [cteRowNumbers] 
    ) t 
    UNION ALL 
    SELECT t.[RowNumber], 
      t.[stringname], 
      s.[stringname] AS [previous_stringname] 
    FROM [cteRowNumbers] AS t 
    INNER JOIN [cteStringNames] AS s 
     ON t.[RowNumber] - 1 = s.[RowNumber] 
) 

SELECT [stringname], 
     [previous_stringname], 
     COUNT(*) AS [count] 
FROM [cteStringNames] 
GROUP BY stringname, previous_stringname 
ORDER BY stringname 
+0

我從來沒有見過這招,這對我來說是新的:)在這種情況下,那麼不需要標識列。當然,那麼使用一個或兩個CTE來獲得結果成爲設計偏好。 – Wil