อะไรคือความแตกต่างระหว่างประเภทข้อมูล SQLite ที่เกี่ยวข้องเช่น INT, INTEGER, SMALLINT และ TINYINT


101

เมื่อสร้างตารางใน SQLite3 ฉันรู้สึกสับสนเมื่อต้องเผชิญกับประเภทข้อมูลที่เป็นไปได้ทั้งหมดซึ่งบ่งบอกถึงเนื้อหาที่คล้ายกันใครสามารถบอกความแตกต่างระหว่างประเภทข้อมูลต่อไปนี้ได้

INT, INTEGER, SMALLINT, TINYINT

DEC, DECIMAL

LONGCHAR, LONGVARCHAR

DATETIME, SMALLDATETIME

มีเอกสารบางอย่างที่แสดงรายการ min./max ความจุของข้อมูลประเภทต่างๆ? ตัวอย่างเช่นฉันเดาว่าsmallintมีค่าสูงสุดมากกว่าtinyintแต่มีค่าน้อยกว่าจำนวนเต็ม แต่ฉันไม่รู้ว่าความจุเหล่านี้คืออะไร

คำตอบ:


95

SQLiteในทางเทคนิคไม่มีประเภทข้อมูลมีคลาสพื้นที่เก็บข้อมูลในระบบการพิมพ์รายการและใช่มันน่าสับสนถ้าคุณคุ้นเคยกับRDBMSes แบบดั้งเดิม ทุกอย่างภายในจะถูกจัดเก็บเป็นข้อความ ประเภทข้อมูลถูกบังคับ / แปลงเป็นตำแหน่งที่เก็บข้อมูลต่างๆตามความสัมพันธ์ (ประเภทข้อมูลที่กำหนดให้กับคอลัมน์)

สิ่งที่ดีที่สุดที่ฉันแนะนำให้คุณทำคือ:

  1. ลืมทุกสิ่งที่คุณเคยรู้เกี่ยวกับประเภทข้อมูลฐานข้อมูลแบบสแตนด์อโลนชั่วคราว

  2. อ่านลิงค์ด้านบนจากSQLiteเว็บไซต์

  3. แยกประเภทตามสคีมาเก่าของคุณและดูว่าพวกเขาจะจับคู่กับอะไร SQLite

  4. ย้ายข้อมูลทั้งหมดไปยังSQLiteฐานข้อมูล

หมายเหตุ:ข้อ จำกัด ประเภทข้อมูลอาจยุ่งยากโดยเฉพาะอย่างยิ่งหากคุณเพิ่มระยะเวลาหรือวันที่หรือสิ่งต่างๆในลักษณะSQLนั้น SQLiteมีฟังก์ชันในตัวน้อยมากสำหรับสิ่งนั้น อย่างไรก็ตามSQLiteมีวิธีง่ายๆสำหรับคุณในการสร้างฟังก์ชันในตัวของคุณเองสำหรับการเพิ่มระยะเวลาและสิ่งต่างๆในลักษณะนั้นผ่านทางsqlite3_create_functionฟังก์ชันไลบรารี คุณจะใช้สถานที่นั้นแทนขั้นตอนการจัดเก็บแบบเดิม


1
ขอบคุณสำหรับคำตอบและลิงค์ นี่หมายความว่าฉันควรยึดติดกับประเภทพื้นฐานของข้อความตัวเลขจำนวนเต็มจริงไม่ใช่หรือ ดูเหมือนจะ จำกัด ฉันมากโดยเฉพาะอย่างยิ่งมาจากพื้นหลัง MSSQL, Foxpro และ Oracle ความนับถือ.
Alan Harris-Reid

6
ฉันเห็นด้วยกับคุณดูเหมือนว่าจะมีข้อ จำกัด ในตอนแรก อย่างไรก็ตามฉันคิดว่าคุณจะพบว่า SQLite นั้นให้อภัยมากในการที่คุณใส่ข้อมูลลงในฐานข้อมูลผ่านระบบความสัมพันธ์ SQLite ไม่ใช่แบบสแตนด์อโลน - ได้รับการออกแบบให้เป็นแบ็กเอนด์ฐานข้อมูลขนาดเล็กที่คุณวางไว้ในแอปพลิเคชันขนาดเล็กเพื่อให้เข้าถึงได้ผ่าน API การเข้าถึงฐานข้อมูลในรหัสเท่านั้น การแก้ปัญหาใน SQLite มักเป็นเรื่องของการค้นหาว่าพวกเขาต้องการให้คุณทำอย่างไร
J.Polfer

ฉันจะยึดติดกับประเภทพื้นฐาน
J.Polfer

4
@Alan: คุณอาจพบว่ามีประโยชน์ในการประกาศคอลัมน์ตัวเลข - ความสัมพันธ์เป็นDATEหรือBOOLEANแต่ฉันจะไม่รบกวนการแยกแยะระหว่างจำนวนเต็มขนาดต่างๆ โดยเฉพาะอย่างยิ่งสำหรับกรณีของINTEGER PRIMARY KEYกรณีที่ชื่อประเภทที่แน่นอนมีความสำคัญ
dan04

"ทุกอย่างถูกเก็บเป็นข้อความ" ดูเหมือนจะไม่ถูกต้องตามsqlite.org/fileformat.htmlซึ่งระบุว่าตัวเลขจะถูกจัดเก็บเป็น varints / float64 แบบกะทัดรัดและมีเพียงหยดและข้อความเท่านั้นที่จัดเก็บเป็นสตริง
phiresky

47

ความแตกต่างคือน้ำตาลซินแทติก ชื่อประเภทย่อยมีเพียงไม่กี่สตริงเท่านั้นที่มีความสำคัญกับประเภทความสัมพันธ์

  • INT, INTEGER, SMALLINT, TINYINT → INTEGER affinity เพราะทั้งหมดมี "INT"
  • LONGCHAR, LONGVARCHAR → TEXT Affinity เนื่องจากมี "CHAR"
  • DEC, DECIMAL, DATETIME, SMALLDATETIME → NUMERIC เนื่องจากไม่มีสตริงย่อยใด ๆ ที่สำคัญ

กฎระเบียบในการกำหนดความสัมพันธ์มีการระบุไว้ในเว็บไซต์ SQLite

หากคุณยืนยันในการพิมพ์อย่างเข้มงวดคุณสามารถใช้งานได้โดยมีCHECKข้อ จำกัด :

CREATE TABLE T (
   N   INTEGER CHECK(TYPEOF(N) = 'integer'),
   Str TEXT CHECK(TYPEOF(Str) = 'text'),
   Dt  DATETIME CHECK(JULIANDAY(Dt) IS NOT NULL)
);

แต่ฉันไม่เคยรำคาญกับมัน

สำหรับความจุของแต่ละประเภท:

  • INTEGERลงนาม 64 บิตเสมอ โปรดทราบว่า SQLite เพิ่มประสิทธิภาพการจัดเก็บข้อมูลจำนวนเต็มขนาดเล็กที่อยู่เบื้องหลังดังนั้น TINYINT จะไม่มีประโยชน์ต่อไป
  • REAL เป็น 64 บิตเสมอ (double ) เสมอ
  • TEXTและBLOBมีขนาดสูงสุดที่กำหนดโดยมาโครตัวประมวลผลล่วงหน้าซึ่งมีค่าเริ่มต้นเป็น 1,000,000,000 ไบต์

1
เคล็ดลับที่ดี ทำทราบว่าวิธีการนี้ไม่จำเป็นต้องมีค่าเพื่อจะแทรก / TYPEOFปรับปรุงเพื่อให้มีการจัดเก็บข้อมูลระดับเดียวกับใน ดังนั้นความพยายามที่จะแทรกข้อความที่จะถูกแปลงเป็นคลาสพื้นที่จัดเก็บ NUMERIC / INTEGER โดย SQlite (กล่าวคือการแปลงดังกล่าวไม่สูญเสียตามsqlite.org/datatype3.html#affinity ) จะล้มเหลว กล่าวอีกนัยหนึ่งวิธีการนี้เข้มงวดกว่าวิธีเฉพาะกิจในการแทรกค่าจากนั้นตรวจสอบความถูกต้องของคลาสหน่วยเก็บข้อมูลที่ใช้ในการจัดเก็บค่าโดย SQLite อย่างน่าอัศจรรย์ สำหรับแนวทางที่อนุญาตมากขึ้นโปรดดูคำตอบของฉันด้านล่าง
eold

10

ส่วนใหญ่มีไว้เพื่อความเข้ากันได้ คุณมีเพียงจำนวนเต็มลอยข้อความและหยดเท่านั้น สามารถจัดเก็บวันที่เป็นตัวเลข (เวลายูนิกซ์เป็นจำนวนเต็มเวลาของไมโครซอฟท์เป็นลอย) หรือเป็นข้อความ


ฉันเคยใช้มันสำหรับโปรเจ็กต์บนเว็บซึ่งในที่สุดทุกอย่างก็ลงเอยด้วยการใส่ข้อความลงในหน้า html อยู่ดี ฉันจ่ายเงินไปกับการแปลงข้อมูลจำนวนมากและเพิ่งใช้ข้อความสำหรับคอลัมน์ส่วนใหญ่ มันได้ผลดี
เจ

3

NULL. ค่านี้เป็นค่า NULL

INTEGER. ค่านี้เป็นจำนวนเต็มลงนามซึ่งเก็บไว้ใน 1, 2, 3, 4, 6 หรือ 8 ไบต์ขึ้นอยู่กับขนาดของค่า

REAL. ค่านี้เป็นค่าทศนิยมที่จัดเก็บเป็นเลขทศนิยม 8 ไบต์ IEEE

TEXT. ค่านี้เป็นสตริงข้อความที่จัดเก็บโดยใช้การเข้ารหัสฐานข้อมูล (UTF-8, UTF-16BE หรือ UTF-16LE)

BLOB. ค่านี้เป็นหยดข้อมูลที่จัดเก็บไว้ตรงตามที่ป้อนข้อมูล


1

นอกเหนือจากคำตอบจาก dan04 หากคุณต้องการแทรกค่าNUMERICอื่นที่ไม่ใช่ศูนย์แบบสุ่มสี่สุ่มห้าที่แทนด้วย a TEXTแต่ต้องแน่ใจว่าข้อความสามารถแปลงเป็นตัวเลขได้:

your_numeric_col NUMERIC CHECK(abs(your_numeric_col) <> 0)

กรณีการใช้งานทั่วไปอยู่ในแบบสอบถามจากโปรแกรมที่ถือว่าข้อมูลทั้งหมดเป็นข้อความ (เพื่อความสม่ำเสมอและความเรียบง่ายเนื่องจาก SQLite ทำเช่นนั้นแล้ว) สิ่งที่ดีเกี่ยวกับเรื่องนี้คืออนุญาตให้สร้างสิ่งนี้:

INSERT INTO table (..., your_numeric_column, ...) VALUES (..., some_string, ...)

ซึ่งสะดวกในกรณีที่คุณใช้ตัวยึดตำแหน่งเนื่องจากคุณไม่จำเป็นต้องจัดการฟิลด์ตัวเลขที่ไม่ใช่ศูนย์ดังกล่าวเป็นพิเศษ ตัวอย่างการใช้sqlite3โมดูลของ Python จะเป็น

conn_or_cursor.execute(
    "INSERT INTO table VALUES (" + ",".join("?" * num_values) + ")",   
    str_value_tuple)  # no need to convert some from str to int/float

ในตัวอย่างข้างต้นค่าทั้งหมดในstr_value_tupleจะถูก Escape และยกมาเป็นสตริงเมื่อส่งผ่านไปยัง SQlite อย่างไรก็ตามเนื่องจากเราไม่ได้ตรวจสอบประเภทอย่างชัดเจนโดยใช้TYPEOFแต่การแปลงเป็นประเภทเท่านั้นจึงจะยังคงทำงานได้ตามต้องการ (กล่าวคือ SQLite จะจัดเก็บเป็นตัวเลขหรือล้มเหลวเป็นอย่างอื่น)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.