SELECT 문에서 "이전 행"값에 액세스하는 방법이 있습니까?


96

테이블의 두 줄 사이의 열 차이를 계산해야합니다. SQL에서 직접 수행 할 수있는 방법이 있습니까? Microsoft SQL Server 2008을 사용하고 있습니다.

나는 다음과 같은 것을 찾고 있습니다.

SELECT value - (previous.value) FROM table

"이전"변수가 가장 최근에 선택한 행을 참조한다고 가정합니다. 물론 그런 선택을하면 n 개의 행이있는 테이블에서 n-1 개의 행이 선택된 것으로 끝날 것입니다. 그것은 아마 아닐 것입니다. 실제로 정확히 필요한 것입니다.

어떤 식 으로든 가능합니까?


6
새로운 시청자에게 유용한 댓글을 추가하는 것뿐입니다. SQL 2012에는 현재 LAG 및 LEAD가 있습니다. :)이 링크 참조 blog.sqlauthority.com/2013/09/22/…
KD

답변:


65

SQL에는 순서 개념이 내장되어 있지 않으므로 의미가 있으려면 일부 열별로 순서를 지정해야합니다. 이 같은:

select t1.value - t2.value from table t1, table t2 
where t1.primaryKey = t2.primaryKey - 1

주문하는 방법을 알고 있지만 현재 값 (예 : 알파벳순으로 주문하려는 경우)에서 이전 값을 얻는 방법을 알지 못하는 경우 표준 SQL에서이를 수행하는 방법을 모르지만 대부분의 SQL 구현에는 확장합니다.

다음은 각 행이 구별되도록 정렬 할 수있는 경우 작동하는 SQL 서버의 방법입니다.

select  rank() OVER (ORDER BY id) as 'Rank', value into temp1 from t

select t1.value - t2.value from temp1 t1, temp1 t2 
where t1.Rank = t2.Rank - 1

drop table temp1

연결을 끊어야하는 경우 ORDER BY에 필요한만큼 열을 추가 할 수 있습니다.


괜찮습니다. 주문은 문제가되지 않습니다. 간단히 예제에서 제거했습니다. 시도해 보겠습니다.
Edwin Jarvis

7
... 이는 기본 키가 순차적으로 생성되는 행이 삭제되지 않습니다 것을 가정하고 선택은 다른 주문 절과와와이없는
MartinStettner

Martin이 맞습니다. 어떤 경우에는 이것이 효과가있을 수 있지만, 생성 된 ID에 의존하지 않고 비즈니스 측면에서 "이전"이 의미하는 바를 정확히 정의해야합니다.
Tom H

맞습니다. SQL Server 확장을 사용하여 개선 사항을 추가했습니다.
RossFabricant 2009

2
"괜찮습니다. 주문은 문제가 아닙니다."에 대한 응답으로 ... 그렇다면 질의를 고려하지 않는 경우 수행하는 작업이므로 쿼리에서 차익 거래 값을 빼는 것이 어떻습니까?
JohnFx 2009

84

지연 기능을 사용하십시오 .

SELECT value - lag(value) OVER (ORDER BY Id) FROM table

Id에 사용되는 시퀀스는 값을 건너 뛸 수 있으므로 Id-1이 항상 작동하는 것은 아닙니다.


1
이것이 PostgreSQL 솔루션입니다. 문제는 MSSQL에 관한 것입니다. MSSQL은 2012+ (버전 같은 기능을 갖는다 msdn.microsoft.com/en-us/en-en/library/hh231256(v=sql.120).aspx을 )
Kromster

10
@KromStern PostgreSQL 솔루션 만이 아닙니다. SQL Window 기능SQL : 2003 표준에 도입되었습니다 .
Hans Ginzel 2015

LAG 함수는 세 가지 매개 변수를 사용할 수 있습니다 LAG(ExpressionToSelect, NumberOfRowsToLag, DefaultValue).. 지연 할 기본 행 수는 1이지만 세트의 시작 부분에 있기 때문에 지연 할 수없는 경우 선택할 수있는 기본값과이를 지정할 수 있습니다.
vaindil

30

오라클, PostgreSQL을, SQL Server 및 더 많은의 RDBMS 엔진이라고 분석 기능을 가지고 LAG그리고 LEAD바로이 일을 그.

2012 년 이전의 SQL Server에서는 다음을 수행해야했습니다.

SELECT  value - (
        SELECT  TOP 1 value
        FROM    mytable m2
        WHERE   m2.col1 < m1.col1 OR (m2.col1 = m1.col1 AND m2.pk < m1.pk)
        ORDER BY 
                col1, pk
        )
FROM mytable m1
ORDER BY
      col1, pk

, COL1주문하는 컬럼은 어디에 있습니까 ?

색인이 있으면 (COL1, PK)이 쿼리가 크게 향상됩니다.


14
SQL Server 2012에는 이제 LAG 및 LEAD도 있습니다.
ErikE 2013-01-06

Hana SQL 스크립트는 LAG 및 LEAD도 지원합니다.
mik

Hive에서 작업하기 위해 여기에 도착한 시청자에게 다른 댓글을 추가하기 위해. LAG 및 LEAD 기능도 있습니다. 문서 : cwiki.apache.org/confluence/display/Hive/…
Jaime Caffarel

27
WITH CTE AS (
  SELECT
    rownum = ROW_NUMBER() OVER (ORDER BY columns_to_order_by),
    value
  FROM table
)
SELECT
  curr.value - prev.value
FROM CTE cur
INNER JOIN CTE prev on prev.rownum = cur.rownum - 1

쿼리에 그룹화가 없으면 올바르게 작동하지만 그룹 내에서만 이전 값에서 값을 빼고 싶다면 동일한 EmployeeID라고하면 어떻게 할 수 있습니까? 이것을 실행하는 Coz는 각 그룹의 상위 2 개 행에 대해서만 작동하며 해당 그룹의 나머지 행에는 작동하지 않습니다. 이를 위해 while 루프에서이 코드를 실행했지만 매우 느린 것 같습니다. 이 시나리오에서 우리가 할 수있는 다른 접근 방식은 무엇입니까? SQL Server 2008에서만 가능합니까?
Hemant Sisodia 2015 년

10

LEFT JOIN 테이블을 조인 조건이 해결 된 상태에서 테이블 자체에 조인하여 "이전"의 특정 정의에 대해 조인 된 테이블 버전에서 일치하는 행이 한 행 이전입니다.

업데이트 : 처음에는 이전 행이없는 조건에 대해 NULL을 사용하여 모든 행을 유지하고 싶다고 생각했습니다. 다시 읽으면 해당 행이 컬링되기를 원하므로 왼쪽 조인이 아닌 내부 조인이 필요합니다.


최신 정보:

최신 버전의 Sql Server에는이를 위해 사용할 수있는 LAG 및 LEAD 창 기능도 있습니다.


3
select t2.col from (
select col,MAX(ID) id from 
(
select ROW_NUMBER() over(PARTITION by col order by col) id ,col from testtab t1) as t1
group by col) as t2

2

선택한 답변은 순서에 공백이없는 경우에만 작동합니다. 그러나 자동 생성 된 ID를 사용하는 경우 롤백 된 삽입으로 인해 시퀀스에 간격이있을 수 있습니다.

이 방법은 간격이있는 경우 작동합니다.

declare @temp (value int, primaryKey int, tempid int identity)
insert value, primarykey from mytable order by  primarykey

select t1.value - t2.value from @temp  t1
join @temp  t2 
on t1.tempid = t2.tempid - 1
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.