SQL Server 2005 T-SQL问题:在省略记录时需要帮助

时间:2009-11-30 07:29:27

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

美好的一天!

我在编写查询时需要帮助..我在下面的表中有记录。如果从先前的记录(new_state)重复后续记录'new_state并且如果它被更改,则条件将不会显示记录在同一天..

这里record_id 1在同一天经历了ff状态:0-> 1-> 2-> 1-> 3-> 4-> 3.状态1变为状态2再次返回状态1(不显示id 2& 3)..与状态3相同(不显示id 5& 6)..

id | record_id| date_changed | old_state | new_state |
1  | 1        | 2009-01-01   | 0         | 1         |
2  | 1        | 2009-01-01   | 1         | 2         | not displayed
3  | 1        | 2009-01-01   | 2         | 1         | not displayed
4  | 1        | 2009-01-01   | 1         | 3         |
5  | 1        | 2009-01-01   | 3         | 4         | not displayed
6  | 1        | 2009-01-01   | 4         | 3         | not displayed

所以结果只显示record_id = 1的2条记录。

id | record_id| date_changed | old_state | new_state |
1  | 1        | 2009-01-01   | 0         | 1         |
4  | 1        | 2009-01-01   | 1         | 3         |

以下是表创建和数据的代码:

IF OBJECT_ID('TempDB..#table','U') IS NOT NULL
      DROP TABLE #table
CREATE TABLE #table
(
id INT identity primary key,
record_id INT,
date_changed DATETIME,
old_state INT,
new_state INT
)
INSERT INTO #table(record_id,date_changed,old_state,new_state)
    SELECT 1,'2009-01-01',0,1 UNION ALL --displayed
    SELECT 1,'2009-01-01',1,2 UNION ALL --not displayed
    SELECT 1,'2009-01-01',2,1 UNION ALL --not displayed
    SELECT 1,'2009-01-01',1,3 UNION ALL --displayed
    SELECT 1,'2009-01-01',3,4 UNION ALL --not displayed
    SELECT 1,'2009-01-01',4,3           --not displayed

INSERT INTO #table(record_id,date_changed,old_state,new_state)
    SELECT 3,'2009-01-01',0,1 UNION ALL --displayed
    SELECT 3,'2009-01-01',1,2 UNION ALL --not displayed
    SELECT 3,'2009-01-01',2,3 UNION ALL --not displayed
    SELECT 3,'2009-01-01',3,4 UNION ALL --not displayed
    SELECT 3,'2009-01-01',4,1           --not displayed

SELECT * FROM #table

我将不胜感激任何帮助..

感谢

关于record_id = 3的清晰度。鉴于此表:

id | record_id| date_changed | old_state | new_state |
7  | 3        | 2009-01-01   | 0         | 1         |
8  | 3        | 2009-01-01   | 1         | 2         | not displayed
9  | 3        | 2009-01-01   | 2         | 3         | not displayed
10 | 3        | 2009-01-01   | 3         | 4         | not displayed
11 | 3        | 2009-01-01   | 4         | 1         | not displayed

当运行record_id = 3的查询时,表结果将是:

id | record_id| date_changed | old_state | new_state |
7  | 3        | 2009-01-01   | 0         | 1         |

谢谢!

更新(2009年12月2日):

特殊情景

id | record_id| date_changed | old_state | new_state |
1  | 4        | 2009-01-01   | 0         | 1         | displayed
2  | 4        | 2009-01-01   | 1         | 2         | displayed
3  | 4        | 2009-01-01   | 2         | 3         | not displayed
4  | 4        | 2009-01-01   | 3         | 2         | not displayed
5  | 4        | 2009-01-01   | 2         | 3         | displayed
6  | 4        | 2009-01-01   | 3         | 4         | not displayed
7  | 4        | 2009-01-01   | 4         | 3         | not displayed

其中new_state 3出现在id 3,5和7 .. id 3将不会显示,因为它位于id 2和id 4之间,它们具有相同的new_state(3)..然后应该显示id 5,因为它有还没有现有的new_state 3 ..

代码段:

IF OBJECT_ID('TempDB..#tablex','U') IS NOT NULL
      DROP TABLE #tablex

CREATE TABLE #tablex
(
id INT identity primary key,
record_id INT,
date_changed DATETIME,
old_state INT,
new_state INT
)
INSERT INTO #tablex(record_id,date_changed,old_state,new_state)
    SELECT 4,'2009-01-01',0,1 UNION ALL --displayed
    SELECT 4,'2009-01-01',1,2 UNION ALL --displayed
    SELECT 4,'2009-01-01',2,3 UNION ALL --not displayed
    SELECT 4,'2009-01-01',3,2 UNION ALL --not displayed
    SELECT 4,'2009-01-01',2,3 UNION ALL --displayed
    SELECT 4,'2009-01-01',3,4 UNION ALL --not displayed
    SELECT 4,'2009-01-01',4,3           --not displayed

我认为构建结果的顺序非常重要。

谢谢!

2 个答案:

答案 0 :(得分:1)

按照步骤获取结果

  • 选择不应在结果中显示的所有项目。
  • 将这些与原始表连接起来,并仅选择那些与不匹配的记录记录。

;WITH cte_table (master_id, master_state, id, record_id, old_state, new_state, level) AS
(
  SELECT  id, old_state, id, record_id, old_state, new_state, 1
  FROM    #table
  UNION ALL
  SELECT  master_id, master_state, #table.id, #table.record_id, #table.old_state, #table.new_state, level + 1
  FROM    cte_table
          INNER JOIN #table ON cte_table.new_state = #table.old_state
                               AND cte_table.record_id = #table.record_id
                               AND cte_table.id < #table.id                               
                               AND cte_table.master_state < #table.old_state
)
SELECT  master_id, t1.*, level
INTO    #result
FROM    #table t1
        INNER JOIN (
            SELECT    master_id, min_child_id = MIN(id), level
            FROM      cte_table
            GROUP BY  master_id, level
        ) t2 ON t2.min_child_id = t1.id

SELECT  t1.*
FROM    #table t1
        LEFT OUTER JOIN (
            SELECT  r1.id
            FROM    #result r1
                    INNER JOIN (
                        SELECT  r1.master_id
                        FROM    #result r1
                                INNER JOIN #result r2 ON r2.new_state = r1.old_state
                                                         AND r2.master_id = r1.master_id
                        WHERE   r1.level = 1
                    ) r2 ON r2.master_id = r1.master_id
        ) r1 ON r1.id = t1.id
WHERE   r1.id IS NULL
        AND t1.old_state < t1.new_state
ORDER BY 1, 2, 3

答案 1 :(得分:1)

SELECT A.*
/*
A.ID, A.old_state, a.new_state, 
B.ID as [Next], b.old_state, b.new_state,
C.ID as [Prev],  c.old_state, c.new_state
*/
FROM #table A LEFT JOIN 
#table B ON A.ID = (B.ID - 1)
LEFT JOIN #table C ON (A.ID - 1) = C.ID
-- WHERE A.old_State <> B.new_State AND A.new_State <> C.old_State
WHERE A.record_id = 1
AND A.old_State <> COALESCE(B.new_State, -1) 
AND A.new_State <> COALESCE(C.old_State, -1)

编辑:我猜,OP需要的是剩下的记录应该被选中,除了当前记录的旧状态与下一记录的新状态(记录中的撤销操作的种类)不同的那些记录,当前记录的新状态应该是与先前记录的旧状态不同。