簡體   English   中英

SQL-如何在沒有多個子選擇的情況下比較更改的列值

[英]SQL - How to compare changing column values without multiple sub-selects

我正在寫一個TSQL查詢。

我有下表,其中A列和B列會偶爾更改。 我對與上一行相比(或當previos行不存在時,即第一行)發生變化的每一行都感興趣。 每個日期將始終是唯一的。

Date                    A   B       SysId
2015-02-01 00:00:00.000 2   1201    949410
2015-01-01 00:00:00.000 3   1201    949410
2014-01-01 00:00:00.000 2   1201    949410
2013-01-01 00:00:00.000 2   1200    949410
2012-01-01 00:00:00.000 2   1200    949410
2011-01-01 00:00:00.000 2   1200    949410
2010-01-01 00:00:00.000 2   1200    949410
2009-01-01 00:00:00.000 2   1200    949410
2008-01-01 00:00:00.000 2   1200    949410
2007-01-01 00:00:00.000 2   1200    949410
2006-01-01 00:00:00.000 2   1200    949410
2005-01-01 00:00:00.000 2   1200    949410
2004-01-01 00:00:00.000 2   1200    949410
2003-01-01 00:00:00.000 2   1200    949410
2002-01-01 00:00:00.000 3   1200    949410
2001-01-01 00:00:00.000 2   1200    949410
2000-01-01 00:00:00.000 3   1200    949410
1999-01-01 00:00:00.000 3   1200    949410
1998-01-01 00:00:00.000 3   1200    949410
1997-01-01 00:00:00.000 3   1200    949410
1996-01-01 00:00:00.000 3   1200    949410
1995-01-01 00:00:00.000 3   1200    949410
1994-01-01 00:00:00.000 3   1200    949410
1993-01-01 00:00:00.000 3   1200    949410
1992-01-01 00:00:00.000 3   1200    949410
1991-01-01 00:00:00.000 3   1200    949410
1990-01-01 00:00:00.000 3   1200    949410
1989-01-01 00:00:00.000 3   1200    949410
1988-01-01 00:00:00.000 3   1200    949410
1987-01-01 00:00:00.000 3   1200    949410
1986-01-01 00:00:00.000 3   1200    949410
1985-01-01 00:00:00.000 3   1200    949410
1984-01-01 00:00:00.000 2   1200    949410

在這種情況下,結果應為:

Date                    A   B       SysId
2015-02-01 00:00:00.000 2   1201    949410
2015-01-01 00:00:00.000 3   1201    949410
2014-01-01 00:00:00.000 2   1201    949410
2003-01-01 00:00:00.000 2   1200    949410
2002-01-01 00:00:00.000 3   1200    949410
2001-01-01 00:00:00.000 2   1200    949410
1985-01-01 00:00:00.000 3   1200    949410
1984-01-01 00:00:00.000 2   1200    949410

由於我們對A或B發生變化的第一行感興趣。

我有一個非常丑陋和昂貴的選擇,可以為我做這件事:

SELECT Date, A, B, SysId
FROM SysHistory fb1
WHERE fb1.SysId = 949410
AND 
(
    (
        ((
            SELECT TOP 1 fb2b.A
            FROM SysHistory fb2b
            WHERE fb2b.Date < fb1.Date 
            AND fb2b.SysId = 949410
            order by Date DESC
        )) <> fb1.StatusId
        OR 
        ((
            SELECT TOP 1 fb2a.A
            FROM SysHistory fb2a
            WHERE fb2a.Date < fb1.Date 
            AND fb2a.SysId= 949410
            order by Date  DESC
        )) IS NULL
    )
    OR
    (
        ((
            SELECT TOP 1 fb3b.B
            FROM SysHistory fb3b
            WHERE fb3b.Date < fb3b.Date 
            AND fb3b.SysId= 949410
            order by Date DESC
        )) <> fb1.StatusId
        OR 
        ((
            SELECT TOP 1 fb3a.B
            FROM SysHistory fb3a
            WHERE fb3a.Date < fb1.Date 
            AND fb3a.SysId = 949410
            order by Date DESC
        )) IS NULL
    )
)
order by Date DESC

請注意,對於每個我我都從上一行獲取頂部的A或B屬性。 由於上一行可能為空(在表中第一行的情況下),所以我還為A和B設置了OR語句,該語句檢查null。

我覺得必須有更好的方法來做到這一點。

在TSQL中,是否可以比較同一子選擇中的多個列? 或者只是一般而言,您將如何改進此查詢? 是否有使其更緊湊或可能更快的方法?

我想我的問題接近最佳實踐,但我認為從技術上講這是一個語法問題。

導入更新我現在注意到,查詢實際上並沒有給我想要的結果。 因此,上面的SQL查詢似乎不起作用。 在這種情況下的結果應該是

Date                    A   B       SysId
2015-02-01 00:00:00.000 2   1201    949410
2015-01-01 00:00:00.000 3   1201    949410
2014-01-01 00:00:00.000 2   1201    949410
2003-01-01 00:00:00.000 2   1200    949410
2002-01-01 00:00:00.000 3   1200    949410
2001-01-01 00:00:00.000 2   1200    949410
1985-01-01 00:00:00.000 3   1200    949410
1984-01-01 00:00:00.000 2   1200    949410

相反,結果是:

Date                    A   B       SysId
2015-02-01 00:00:00.000 2   1201    949410
2015-01-01 00:00:00.000 3   1201    949410
2003-01-01 00:00:00.000 2   1200    949410
2002-01-01 00:00:00.000 3   1200    949410
2001-01-01 00:00:00.000 2   1200    949410
1985-01-01 00:00:00.000 3   1200    949410
1984-01-01 00:00:00.000 2   1200    949410

您可以對數據應用ROW_NUMBER() ,以便可以執行自聯接以查找先前的行:

;WITH Numbered as (
  SELECT Date, A, B, SysId,
    ROW_NUMBER() OVER (ORDER BY Date desc) as rn
  FROM SysHistory fb1
  WHERE fb1.SysId = 949410
)
select n1.*
from Numbered n1
   left join
     Numbered n2
        on n1.rn = n2.rn - 1
where
  n2.Date is null or --If you want to include the earliest row
  n1.A <> n2.A or
  n1.B <> n2.B

結果(將示例數據放入名為@SysHistory的表變量中,在查詢上進行了更改以引用它,並使用[Date] @SysHistory Date列,因為使用類型名作為列名通常是一個壞主意):

Date                    A           B           SysId       rn
----------------------- ----------- ----------- ----------- --------------------
2015-02-01 00:00:00.000 2           1201        949410      1
2015-01-01 00:00:00.000 3           1201        949410      2
2014-01-01 00:00:00.000 2           1201        949410      3
2003-01-01 00:00:00.000 2           1200        949410      14
2002-01-01 00:00:00.000 3           1200        949410      15
2001-01-01 00:00:00.000 2           1200        949410      16
1985-01-01 00:00:00.000 3           1200        949410      32
1984-01-01 00:00:00.000 2           1200        949410      33

這似乎與您的預期結果相符(除了我的額外專欄)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM