基于SQL中的下一个和上一个记录进行排序

时间:2015-05-27 09:03:14

标签: sql sql-server sql-server-2005

我试图通过考虑下一个和之前的记录来订购特定的查询,但我似乎无法完成它。我想通过数字和字母来订购,但是,例如,如果数字1的最后一个字母等于数字2中的一个字母,我想更改顺序,以便该字母与以下字母匹配记录。

Create script and SQL fiddle demo

create table Parent (
id [bigint] IDENTITY(1,1), 
number bigint NOT NULL,
PRIMARY KEY (id)
)
GO

create table Child (
id [bigint] IDENTITY(1,1), 
parentId BIGINT, 
letter VARCHAR(1) NOT NULL,
PRIMARY KEY (id),
UNIQUE (parentId, Letter),
FOREIGN KEY (parentId) REFERENCES Parent(id)
)
GO

INSERT Parent (number) VALUES (1)
INSERT Parent (number) VALUES (2)
INSERT Parent (number) VALUES (3)

INSERT Child (parentId, letter) VALUES (1, 'A')
INSERT Child (parentId, letter) VALUES (1, 'C')
INSERT Child (parentId, letter) VALUES (2, 'B')
INSERT Child (parentId, letter) VALUES (2, 'C')
INSERT Child (parentId, letter) VALUES (3, 'B')
INSERT Child (parentId, letter) VALUES (3, 'D')

当前查询

目前我正在使用此查询进行排序:

SELECT P.number, C.letter 
FROM Child C
JOIN Parent P ON C.parentId = P.id
ORDER BY P.number, C.letter

当前结果集

number               letter
-------------------- ------
1                    A
1                    C
2                    B
2                    C
3                    B
3                    D

预期结果集

为了澄清我实际想做什么,这里是预期的结果集(切换了2号C和B)。

number               letter
-------------------- ------
1                    A
1                    C
2                    C --switched
2                    B --switched
3                    B
3                    D

其他要求和问题

  • 必须在 SQL SERVER 2005 中工作。
  • 有一个场景,每个号码使用3个字母,如果它只使用最佳匹配,我很高兴。
  • 我实际上也对SQL Server的更高版本(用于学习)的解决方案感兴趣,但那些没有回答我的问题。

有人能指出我正确的方向如何做到这一点?

1 个答案:

答案 0 :(得分:6)

你可以这样做。

  1. 使用ROW_NUMBER()PARTITION BY
  2. 标识每位家长的第一个和最后一个字母
  3. 将前一个id的最后一条记录与下一个id的第一条记录相匹配。
  4. 检查第二个父ID是否有任何与上面选择的字母匹配的字母
  5. 使用LEFT JOIN并使用CASEISNULL为信件匹配的id记录设置更高的优先级
  6. <强>查询

    ;WITH CTE AS 
    (
    SELECT id,ParentID,letter,
    ROW_NUMBER()OVER(PARTITION BY parentId ORDER BY ID) first_element,
    ROW_NUMBER()OVER(PARTITION BY parentId ORDER BY ID DESC) Last_element
    FROM Child
    ), CTE2 AS 
    (
    SELECT c1.id,c1.parentid,c1.letter,c2.parentid as c2parentid
    FROM CTE c1
    INNER JOIN CTE c2
    ON c1.last_element = 1
    AND c2.first_element = 1
    AND c1.id +1 = c2.id
    ), CTE3 AS 
    (
    SELECT C.parentid,C.id
    FROM CTE2
    INNER JOIN child C ON CTE2.c2parentid = C.parentid
    AND C.letter = CTE2.letter
    )
    SELECT P.number, C.letter
    FROM Child C
    JOIN Parent P ON C.parentId = P.id
    LEFT JOIN CTE3 ON CTE3.id = C.id
    ORDER BY P.number, ISNULL(CTE3.id,0) DESC, C.letter 
    

    <强>输出

    number  letter
    1   A
    1   C
    2   C
    2   B
    3   B
    3   D
    

    SQL Fiddle

    修改

    如果您的ids不是连续的,则可以像这样更改CTE1CTE2以使用ROW_NUMBER()OVER(ORDER BY ID) seq_id

    ;WITH CTE AS 
    (
    SELECT id,ParentID,letter,
    ROW_NUMBER()OVER(ORDER BY ID) seq_id,
    ROW_NUMBER()OVER(PARTITION BY parentId ORDER BY ID) first_element,
    ROW_NUMBER()OVER(PARTITION BY parentId ORDER BY ID DESC) Last_element
    FROM Child
    ), CTE2 AS 
    (
    SELECT c1.id,c1.parentid,c1.letter,c2.parentid as c2parentid
    FROM CTE c1
    INNER JOIN CTE c2
    ON c1.last_element = 1
    AND c2.first_element = 1
    AND c1.seq_id + 1 = c2.seq_id
    )
    

    其余代码保持不变。

    SQL Fiddle