Saya perlu menghitung selisih kolom antara dua baris tabel. Apakah ada cara agar saya dapat melakukan ini secara langsung di SQL? Saya menggunakan Microsoft SQL Server 2008.
Saya mencari sesuatu seperti ini:
SELECT value - (previous.value) FROM table
Bayangkan variabel "sebelumnya" merujuk ke baris yang terakhir dipilih. Tentu saja dengan pemilihan seperti itu saya akan berakhir dengan n-1 baris yang dipilih dalam tabel dengan n baris, itu bukan mungkin, sebenarnya itulah yang saya butuhkan.
Apakah itu mungkin dalam beberapa hal?
sql
sql-server
sql-server-2008
Edwin Jarvis
sumber
sumber
Jawaban:
SQL tidak memiliki gagasan urutan bawaan, jadi Anda perlu mengurutkan berdasarkan beberapa kolom agar ini bermakna. Sesuatu seperti ini:
select t1.value - t2.value from table t1, table t2 where t1.primaryKey = t2.primaryKey - 1
Jika Anda tahu cara memesan sesuatu tetapi tidak tahu cara mendapatkan nilai sebelumnya yang diberikan nilai saat ini (EG, Anda ingin mengurutkan menurut abjad) maka saya tidak tahu cara melakukannya dalam SQL standar, tetapi sebagian besar implementasi SQL akan memilikinya ekstensi untuk melakukannya.
Berikut adalah cara untuk SQL server yang berfungsi jika Anda dapat mengurutkan baris sedemikian rupa sehingga masing-masing baris berbeda:
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
Jika Anda perlu memutuskan hubungan, Anda dapat menambahkan kolom sebanyak yang diperlukan ke ORDER BY.
sumber
Gunakan fungsi lag :
SELECT value - lag(value) OVER (ORDER BY Id) FROM table
Urutan yang digunakan untuk Id dapat melewati nilai, jadi Id-1 tidak selalu berfungsi.
sumber
LAG(ExpressionToSelect, NumberOfRowsToLag, DefaultValue)
. Jumlah baris default yang akan ditunda adalah 1, tetapi Anda dapat menentukannya dan nilai default untuk dipilih jika tidak memungkinkan untuk tertinggal karena Anda berada di awal set.Oracle, PostgreSQL, SQL Server, dan banyak lagi mesin RDBMS memiliki fungsi analitik yang dipanggil
LAG
danLEAD
melakukan hal ini.Di SQL Server sebelum 2012, Anda perlu melakukan hal berikut:
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
, di mana
COL1
kolom tempat Anda memesan.Memiliki indeks
(COL1, PK)
akan sangat meningkatkan kueri ini.sumber
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
sumber
LEFT JOIN tabel itu sendiri, dengan kondisi join berhasil sehingga baris yang cocok dalam versi tabel yang digabungkan adalah satu baris sebelumnya, untuk definisi khusus Anda tentang "sebelumnya".
Pembaruan: Awalnya saya berpikir Anda ingin menyimpan semua baris, dengan NULL untuk kondisi di mana tidak ada baris sebelumnya. Membacanya lagi Anda hanya ingin baris itu disingkirkan, jadi Anda harus gabungan dalam daripada gabungan kiri.
Memperbarui:
Versi Sql Server yang lebih baru juga memiliki fungsi LAG dan LEAD Windowing yang dapat digunakan untuk ini juga.
sumber
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
sumber
Jawaban yang dipilih hanya akan berfungsi jika tidak ada celah dalam urutan. Namun jika Anda menggunakan id yang dibuat secara otomatis, kemungkinan ada celah dalam urutan karena penyisipan yang dibatalkan.
Metode ini akan berfungsi jika Anda memiliki celah
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
sumber