Saya memiliki tabel data sensor. Setiap baris memiliki id sensor, stempel waktu, dan bidang lainnya. Saya ingin memilih satu baris dengan cap waktu terbaru untuk setiap sensor, termasuk beberapa bidang lainnya.
Saya pikir solusinya adalah mengelompokkan berdasarkan id sensor dan kemudian memesan berdasarkan max (timestamp) seperti ini:
SELECT sensorID,timestamp,sensorField1,sensorField2
FROM sensorTable
GROUP BY sensorID
ORDER BY max(timestamp);
Ini memberi saya kesalahan yang mengatakan bahwa "sensorField1 harus muncul di grup menurut klausa atau digunakan secara agregat".
Apa cara yang benar untuk mengatasi masalah ini?
sql
greatest-n-per-group
terus terang
sumber
sumber
Jawaban:
Demi kelengkapan, berikut kemungkinan solusi lain:
SELECT sensorID,timestamp,sensorField1,sensorField2 FROM sensorTable s1 WHERE timestamp = (SELECT MAX(timestamp) FROM sensorTable s2 WHERE s1.sensorID = s2.sensorID) ORDER BY sensorID, timestamp;
Cukup menjelaskan diri sendiri menurut saya, tetapi berikut ini info selengkapnya jika Anda mau, serta contoh lainnya. Ini dari manual MySQL, tetapi kueri di atas berfungsi dengan setiap RDBMS (menerapkan standar sql'92).
sumber
Ini dapat dilakukan dengan cara yang relatif elegan dengan menggunakan
SELECT DISTINCT
, sebagai berikut:SELECT DISTINCT ON (sensorID) sensorID, timestamp, sensorField1, sensorField2 FROM sensorTable ORDER BY sensorID, timestamp DESC;
Di atas berfungsi untuk PostgreSQL (beberapa info lebih lanjut di sini ) tetapi saya pikir juga mesin lain. Jika tidak jelas, yang dilakukan adalah mengurutkan tabel berdasarkan ID sensor dan stempel waktu (terbaru ke terlama), lalu mengembalikan baris pertama (yaitu stempel waktu terbaru) untuk setiap ID sensor unik.
Dalam kasus penggunaan saya, saya memiliki ~ 10 juta pembacaan dari ~ 1K sensor, jadi mencoba untuk menggabungkan tabel dengan dirinya sendiri pada filter berbasis timestamp sangat intensif sumber daya; di atas membutuhkan beberapa detik.
sumber
Anda dapat menggabungkan tabel dengan dirinya sendiri (pada sensor id), dan menambahkan
left.timestamp < right.timestamp
sebagai kondisi penggabungan. Kemudian Anda memilih baris, di manaright.id
adalahnull
. Voila, Anda mendapat entri terbaru per sensor.http://sqlfiddle.com/#!9/45147/37
SELECT L.* FROM sensorTable L LEFT JOIN sensorTable R ON L.sensorID = R.sensorID AND L.timestamp < R.timestamp WHERE isnull (R.sensorID)
Tapi harap dicatat, bahwa ini akan sangat intensif sumber daya jika Anda memiliki sedikit id dan banyak nilai! Jadi, saya tidak akan merekomendasikan ini untuk semacam Mengukur-Barang, di mana setiap Sensor mengumpulkan nilai setiap menit. Namun dalam Use-Case, di mana Anda perlu melacak "Revisi" dari sesuatu yang hanya "kadang-kadang" berubah, itu mudah.
sumber
Anda hanya dapat memilih kolom yang ada di grup atau digunakan dalam fungsi agregat. Anda dapat menggunakan gabungan agar ini berfungsi
select s1.* from sensorTable s1 inner join ( SELECT sensorID, max(timestamp) as mts FROM sensorTable GROUP BY sensorID ) s2 on s2.sensorID = s1.sensorID and s1.timestamp = s2.mts
sumber
select * from sensorTable where (sensorID, timestamp) in (select sensorID, max(timestamp) from sensorTable group by sensorID)
.WITH SensorTimes As ( SELECT sensorID, MAX(timestamp) "LastReading" FROM sensorTable GROUP BY sensorID ) SELECT s.sensorID,s.timestamp,s.sensorField1,s.sensorField2 FROM sensorTable s INNER JOIN SensorTimes t on s.sensorID = t.sensorID and s.timestamp = t.LastReading
sumber
Ada satu jawaban umum yang belum saya lihat di sini, yaitu Fungsi Jendela. Ini adalah alternatif untuk sub-kueri terkait, jika DB Anda mendukungnya.
SELECT sensorID,timestamp,sensorField1,sensorField2 FROM ( SELECT sensorID,timestamp,sensorField1,sensorField2 , ROW_NUMBER() OVER( PARTITION BY sensorID ORDER BY timestamp ) AS rn FROM sensorTable s1 WHERE rn = 1 ORDER BY sensorID, timestamp;
Saya sebenarnya menggunakan ini lebih dari sub-kueri yang berkorelasi. Jangan ragu untuk menghina saya di komentar tentang efisiensi, saya tidak terlalu yakin bagaimana hal itu menumpuk dalam hal itu.
sumber
Saya memiliki sebagian besar masalah yang sama dan akhirnya mendapatkan solusi berbeda yang membuat jenis masalah ini sepele untuk ditanyakan.
Saya memiliki tabel data sensor (data 1 menit dari sekitar 30 sensor)
dan saya memiliki tabel sensor yang sebagian besar berisi hal-hal statis tentang sensor tetapi bidang yang relevan adalah:
TvLastupdate dan tvLastValue disetel di pemicu saat menyisipkan ke tabel SensorReadings. Saya selalu memiliki akses langsung ke nilai-nilai ini tanpa perlu melakukan kueri yang mahal. Ini sedikit mendenormalisasi. Kueri itu sepele:
SELECT idSensor,Description,tvLastUpdate,tvLastValue FROM Sensors
Saya menggunakan metode ini untuk data yang sering ditanyakan. Dalam kasus saya, saya memiliki tabel sensor, dan tabel peristiwa besar, yang memiliki data yang masuk pada tingkat menit DAN lusinan mesin memperbarui dasbor dan grafik dengan data tersebut. Dengan skenario data saya, metode trigger-and-cache bekerja dengan baik.
sumber