Cara terbaik untuk menyimpan unit dalam basis data

21

Saya telah mewarisi database besar (SQLServer) dengan ratusan kolom yang mewakili jumlah satu atau lain hal. Unit untuk nilai-nilai ini (misalnya "galon", "inci", dll) disimpan dalam bidang MS_Description dari Extended Properties. Saya bertanya-tanya apakah ada cara yang lebih baik untuk menyimpan informasi ini. Saya kira itu baik untuk keperluan dokumentasi, tetapi akan sulit untuk membuat perhitungan unit-konversi yang kuat berdasarkan data ini. Pada titik ini saya tidak siap untuk melakukan perubahan invasif, tetapi jika saya mendapatkan kesempatan untuk melakukannya, apa Praktik Terbaik yang direkomendasikan dalam hal ini? Pilihan, dari atas kepala saya, mungkin termasuk:

  • Ubah nama kolom menjadi unit yang disertakan (misalnya, "TotalVolumeInGallons". Ini akan membuat informasi sedikit lebih mudah tersedia, tetapi tampaknya masih lemah bagi saya.)
  • Tambahkan kolom "Unit" yang terpisah untuk berkorespondensi dengan setiap kolom "Jumlah" (kolom ini bisa berupa nvarchar ATAU itu bisa menjadi kunci asing ke tabel Unit terpisah yang mungkin membuatnya lebih mudah untuk menghitung konversi unit. Di sisi lain, menambahkan begitu banyak kolom yang dapat menggandakan ukuran basis data saya - dengan data yang sangat berlebihan.)
  • Buat bidang baru di Extended Properties yang didedikasikan khusus untuk unit. (Sayangnya, saya tidak berpikir ini bisa menjadi kunci asing ke tabel Unit.)
  • Apakah ada ide lain yang saya abaikan?

UPDATE: Setelah membaca jawaban @Todd Everett, solusi yang mungkin muncul pada saya, jadi saya akan melanjutkan dan menjawab pertanyaan saya sendiri. (Lihat di bawah)

kmote
sumber
Praktik terbaik adalah memiliki sistem pengukuran tunggal yang digunakan secara universal dan konsisten di seluruh aplikasi. SI akan menjadi sistem pilihan. Nilai-nilai dalam sistem lain akan dikonversi selama memuat atau di lapisan presentasi, di mana setiap pengguna dapat memilih set yang diinginkannya.
Michael Green

Jawaban:

12

Karena Anda menyebutkan ratusan kolom saya akan mempertimbangkan desain EAV . Sementara Joe Celko memperingatkan ini , saya pikir itu mungkin berlaku dalam kasus penggunaan Anda. Kedengarannya seperti semua "jumlah" Anda adalah angka, sehingga Anda akan menghindari masalah casting yang dijelaskan Joe dan kebutuhan untuk membuat setiap "nilai" string. Ini akan bekerja lebih baik jika semua jumlahnya adalah bilangan bulat, tetapi dapat bekerja juga jika beberapa desimal. Diberi Units of Measure, Anda dapat melangkah lebih jauh dan menerapkan model gaya "data universal" yang didasarkan pada artikel ini oleh David Hay dan juga menguraikan dalam bukunya, Data Model Patterns: Conventions of Thought. Model ini memiliki keuntungan tambahan untuk mengonfigurasi "jumlah" mana yang berlaku untuk "hal" mana jika Anda membutuhkannya. Satu langkah tambahan yang ditunjukkan dalam buku pada halaman 162 adalah tabel Unit Konversi Ukur yang dapat Anda gunakan untuk mengonversi antara Unit Pengukuran yang berbeda. Berikut ini sebuah contoh:

UOM Conversion              

UOM From    UOM To        Cal Step  Operator Factor Constant
Kilograms   Pounds        1         *        2.2
Celsius     Fahrenheit    1         *        1.8
Celsius     Fahrenheit    2         +               32

Ini mengatakan bahwa untuk mengkonversi dari Kg ke Lb langkah pertama adalah mengalikan Kg dengan 2.2. Ada juga konstanta jika konversi juga harus menyertakan nilai konstan, dan kemampuan untuk membuat beberapa langkah. Jadi, ketika mengonversi katakan Celsius ke Fahrenheit, Anda mengalikan Celsius dengan 1,8 dan kemudian menambahkan 32. Kuncinya adalah dari UOM, ke UOM, dan Langkah Perhitungan.

Itu adalah nilai 2 sen saya. Saya harap referensi ini memberi Anda beberapa makanan yang baik untuk dipikirkan jika Anda pernah mendapatkan kesempatan untuk melakukan reboot pada desain saat ini.

Todd Everett
sumber
Terima kasih untuk makanan yang sangat menarik untuk dipikirkan - saya belajar banyak. Namun, saya tidak berpikir EAV adalah model yang tepat dalam kasus saya (jika saya memahami saran Anda dengan benar) karena, meskipun kami memiliki 100 kolom, mereka tidak jarang. Namun, DID ini memicu ide terkait (lihat PEMBARUAN di posting asli saya).
kmote
Gagasan Anda kedengarannya bagus bagi saya - saya tidak bisa memikirkan masalah apa pun selain apa yang sudah Anda tunjukkan. Tetapi jika kolom dapat diubah namanya / diubah itu akan menjadi masalah dalam desain apa pun. Inilah saat kolaborasi itu menyenangkan - sebuah ide muncul yang tidak ada di antara kami yang berpikir untuk memulai!
Todd Everett
8

Semua bekerja

Perhatikan bahwa dalam kasus kedua, Anda tidak dapat menambahkan apel dan jeruk, sehingga datanya sangat mudah menjadi sasaran interpretasi yang salah.

Perhatikan juga bahwa konversi tidak bisa sangat aman dan rentan terhadap kesalahan pembulatan, luapan, dll.

Selain itu, ada masalah fisik seperti berat jenis dan suhu. Mengubah 20 galon air menjadi pound akan mengharuskan Anda untuk mengetahui kepadatan air. Tetapi kerapatan air berubah dengan suhu, jadi Anda mungkin perlu mengetahui kerapatan sezaman dengan pengukuran atau suhu serupa dan menggunakan faktor koreksi volume.

Dalam kasus properti Extended, itu hanya baik untuk dokumentasi - nama kolom yang baik lebih baik untuk dokumentasi. Masalah dengan kolom tersirat berada di unit tetap dengan nama adalah bahwa Anda akhirnya menempatkan diri Anda di sudut ketika Anda mengubah unit pengukuran - klien baru ingin minyak dalam barel dan bukan galon - dan itu akan baik-baik saja karena data mereka ada di database sendiri, tetapi nama kolom sekarang menyesatkan.

Pilihan lain adalah untuk menyimpan versi kanonik dalam satuan tetap (yaitu selalu kilogram dan meter) di samping berbagai pengukuran asli. Operasi agregat pada unit tetap harus baik-baik saja (kecuali Anda tidak akan menambah suhu, misalnya), tetapi Anda tidak kehilangan pengukuran aslinya.

Cade Roux
sumber
1
Potensi "salah tafsir" yang Anda sebutkan adalah persis salah satu kekhawatiran yang saya miliki tentang arsitektur saat ini dari database ini - dan sesuatu yang saya coba cari cara untuk mengurangi.
kmote
1
poin bagus tentang potensi kelemahan dari solusi nama-kolom.
kmote
1
@kmote Ini bukan masalah sederhana - kami memiliki laporan di mana transaksi individu mungkin memiliki beragam unit pengukuran asli, tetapi ada juga total - yang merupakan total setelah konversi ke unit yang dipilih pengguna.
Cade Roux
7

Solusi sederhana yang telah bekerja dengan baik bagi saya di masa lalu adalah menyimpan semua data Anda di unit 'basis'. Misalnya, unit dasar Anda untuk panjang mungkin milimeter dan unit dasar Anda untuk berat mungkin kilogram. Solusi ini dapat mengakibatkan kebutuhan untuk mengubah beberapa data Anda yang ada menjadi unit dasar, jika belum.

Setelah Anda memiliki semua data di unit dasar standar, tidak perlu menyimpan unit dalam database itu sendiri, karena sekarang asumsi sistem lebar. Unit yang ditampilkan diperlukan untuk setiap jenis unit (mis. Apakah menampilkan panjang mm, inci, cm, m) menjadi masalah domain aplikasi / klien, yang dapat disimpan ke penyimpanan lokal.

Tabel konversi unit untuk mengkonversi antara berbagai unit yang didukung dapat di-hardcode dalam aplikasi Anda, karena unit baru dari perubahan ukuran sangat jarang.

NB solusi terkait untuk masalah lain adalah ketika menyimpan cap waktu dalam database untuk selalu menyimpannya di unit 'base' - UTC .

T&J terkait lainnya pada topik ...

dodgy_coder
sumber
5

Karena setiap unit dapat dikonversi ke unit lain dari jenis yang sama Dengan rumus:

y = ((x + xOffset) * multiplicand / denominator) + yOffset

Saya akan membuat tabel yang berisi tipe unit plus 4 nilai ini.

From Unit     To Unit      Unit Type    From Offset    Multiplicand    Denominator    To Offset
'milligrams'  'grams'      'mass'       0              1               1000           0
'grams'      'kilograms'   'mass'       0              1               1000           0
'grams'      'ounces'      'mass'       0              100000          2835           0
'ounces'     'pound'       'mass'       0              1               16             0

Setelah menambahkan semua pengukuran yang akan dikonversi ke dan dari berada di kedua sisi daftar, jalankan Kueri tempat Anda memasukkan operasi terbalik dengan hanya meniadakan offset dan bertukar multiplicand dan denominator dan To Unit dan From Unit.

Untuk menambahkan Konversi antara semua jenis, gabungan silang Dengan beberapa filter dapat menyisipkan Konversi yang tersisa.

peroyhav
sumber
3

Setelah membaca jawaban @Todd Everett, sebuah solusi muncul pada saya, jadi saya akan melanjutkan dan menjawab pertanyaan saya sendiri. Apa yang saya pikir saya akan lakukan adalah untuk membuat terpisah ColumnUnitsmeja, dengan empat kolom: Schema, Table, Column, UnitsID(di mana UnitsID adalah FK untuk terpisah UnitsOfMeasuretabel), sehingga pemetaan setiap kolom yang diberikan kepada Unit yang terkait Ukur. Jelas kerugian terbesar dari ide ini adalah bahwa pengembang harus ingat untuk mengedit tabel ini setiap kali mereka mengganti nama kolom atau tabel [ mungkin menggunakan pemicu DDL ? ], jika tidak, sistem akan rusak. Tetapi dengan asumsi perubahan nama seperti itu jarang terjadi, dan toko kecil (hanya satu orang, dalam kasus saya), arsitektur ini harus bisa diterapkan. Keuntungannya adalah bahwa tidak ada perubahan invasif yang harus dilakukan pada DB saat ini, dan saya hanya perlu menyimpan nilai satu kali untuk setiap kolom, daripada satu kali per baris seperti yang dibutuhkan oleh opsi kedua dalam posting asli saya.

kmote
sumber
teka-teki menarik ... dan ide menarik yang Anda miliki. ide Anda akan membuatnya lebih mudah untuk dicari, tetapi tampaknya tidak mencapai banyak. Anda baru saja memindahkan data referensi ke tempat yang berbeda. apa yang paling mengganggu saya tentang desain ini
Sir Swears-a-lot
... adalah bahwa jika suatu item memiliki lebih banyak atribut Anda masih perlu menambahkan lebih banyak kolom. untuk alasan itu saya suka saran @todd everett tentang desain eav.
Sir Swears-a-lot