SQL Server 2005 T-SQL Проблема: Нужна помощь в пропуске записей - PullRequest
4 голосов
/ 30 ноября 2009

Добрый день!

Мне нужна помощь в написании запроса. У меня есть записи в таблице ниже. Условие: записи не должны отображаться, если повторяющиеся записи new_state были повторены из предыдущих записей (new_state) и изменились в тот же день ..

здесь record_id 1 прошел через состояния ff: 0-> 1-> 2-> 1-> 3-> 4-> 3 в тот же день. Состояние 1 было изменено на состояние 2, затем обратно в состояние 1 снова (идентификаторы 2 и 3 не будут отображаться) .. то же самое с состоянием 3 (идентификаторы 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

, поэтому результат будет отображать только 2 записи для record_id = 1 ..

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         |

Спасибо!

ОБНОВЛЕНИЕ (02.12.2009):

Специальный сценарий

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 появляется на идентификаторах 3,5 и 7 .. идентификатор 3 не будет отображаться, поскольку он находится между идентификаторами 2 и 4, которые имеют одинаковое new_state (3). Тогда должен отображаться идентификатор 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 ]

1 голос
/ 30 ноября 2009
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 нуждается в том, чтобы оставшаяся запись была выбрана, за исключением тех, где старое состояние текущей записи не совпадает с новым состоянием следующей записи (вид операции отмены в записях) и новое состояние текущей записи должно не совпадает со старым состоянием предыдущей записи.

1 голос
/ 30 ноября 2009

Выполните следующие шаги, чтобы получить результат

  • выбрать все элементы, которые не должны появляться в результате.
  • соедините их слева с исходной таблицей и выберите только те записи, которые не соответствуют , не должны появляться запись.

.

;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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...