มีเอกสารสำหรับประเภทคอลัมน์ Rails หรือไม่?


181

ฉันกำลังมองหามากกว่ารายการประเภทง่าย ๆที่พบในหน้านี้ :

: primary_key,: string,: text,: จำนวนเต็ม,: float,: ทศนิยม,: datetime,: timestamp,: เวลา,: วันที่,: วันที่,: ไบนารี,: บูลีน

แต่มีเอกสารใดบ้างที่กำหนดฟิลด์เหล่านี้จริง ๆ

โดยเฉพาะ:

  • ความแตกต่างระหว่าง:stringและ:textคืออะไร
  • ระหว่าง:floatและ:decimal?
  • อะไรคือคุณสมบัติที่แตกต่างของ:time, :timestampและ:datetime?

ความแตกต่างของประเภทเหล่านี้มีการบันทึกไว้ทุกที่หรือไม่?

แก้ไข: คะแนนของการใช้งานแพลตฟอร์ม DB ไม่เกี่ยวข้องกับคำถามที่ฉันพยายามถาม ถ้า, บอก, :datetimeไม่มีความหมายที่กำหนดไว้ในเอกสารประกอบของ Rails แล้ว db-adapter-writer จะทำอะไรเมื่อเลือกประเภทคอลัมน์ที่สอดคล้องกัน?


1
อะไรคือข้อแก้ตัวที่ฉันเลือกใช้คำสิ่งที่เรียกว่า เช่นพวกเขามีเขตข้อมูลหรือคุณลักษณะหรืออะไร ฉันกำลังค้นหาสิ่งอื่นที่ไม่ใช่:stringและ:textและฉันไม่สามารถหาสิ่งอื่นนอกเหนือจากนี้ ดังนั้นฉันแค่สงสัยในการอ้างอิงในอนาคต
l1zZY

2
@ l1zZY คำที่คุณอาจมองหาคือ "ประเภทข้อมูล"
thatpaintingelelant

คำตอบ:


397

แนวทางที่สร้างจากประสบการณ์ส่วนตัว:

  • สตริง :
    • จำกัด ที่ 255 อักขระ (ขึ้นอยู่กับ DBMS)
    • ใช้สำหรับฟิลด์ข้อความสั้น ๆ (ชื่ออีเมลและอื่น ๆ )
  • ข้อความ :
    • ความยาวไม่ จำกัด (ขึ้นอยู่กับ DBMS)
    • ใช้สำหรับความคิดเห็นโพสต์บล็อก ฯลฯ กฎทั่วไปง่ายๆ: ถ้ามันถูกจับผ่าน textarea ให้ใช้ Text สำหรับการป้อนข้อมูลโดยใช้ฟิลด์ข้อความให้ใช้สตริง
  • จำนวนเต็ม :
    • จำนวนทั้งหมด
  • ลอย :
    • ตัวเลขทศนิยมที่เก็บไว้ด้วยความแม่นยำจุดลอย
    • ความแม่นยำได้รับการแก้ไขซึ่งอาจเป็นปัญหาสำหรับการคำนวณบางอย่าง โดยทั่วไปไม่ดีสำหรับการดำเนินการทางคณิตศาสตร์เนื่องจากการปัดเศษที่ไม่ถูกต้อง
  • ทศนิยม :
    • ตัวเลขทศนิยมที่เก็บไว้ด้วยความแม่นยำที่แตกต่างกันไปตามสิ่งที่จำเป็นในการคำนวณ ใช้สิ่งเหล่านี้สำหรับคณิตศาสตร์ที่ต้องแม่นยำ
    • ดูโพสต์นี้สำหรับตัวอย่างและคำอธิบายในเชิงลึกเกี่ยวกับความแตกต่างระหว่างการลอยและทศนิยม
  • บูลีน :
    • ใช้เพื่อเก็บแอตทริบิวต์จริง / เท็จ (เช่นสิ่งที่มีเพียงสองสถานะเช่นเปิด / ปิด)
  • ไบนารี :
    • ใช้เพื่อจัดเก็บรูปภาพภาพยนตร์และไฟล์อื่น ๆ ในรูปแบบดั้งเดิมดิบในกลุ่มข้อมูลที่เรียกว่าblobs
  • : primary_key
    • ประเภทข้อมูลนี้เป็นตัวยึดตำแหน่งที่ Rails แปลเป็นคีย์ข้อมูลหลักประเภทใดก็ได้ที่ฐานข้อมูลของคุณต้องการ (เช่นserial primary keyใน postgreSQL) การใช้งานค่อนข้างซับซ้อนและไม่แนะนำ
    • ใช้ข้อ จำกัด ของรูปแบบและการย้ายข้อมูล (เช่นvalidates_uniqueness_ofและadd_indexพร้อม:unique => trueตัวเลือก) แทนการจำลองการทำงานของคีย์หลักในฟิลด์ใดฟิลด์หนึ่งของคุณเอง
  • วันที่ :
    • เก็บเฉพาะวันที่ (ปี, เดือน, วัน)
  • เวลา :
    • เก็บเฉพาะเวลา (ชั่วโมงนาทีวินาที)
  • วันที่และเวลา :
    • ร้านค้าทั้งวันที่และเวลา
  • การประทับเวลา
    • ร้านค้าทั้งวันที่และเวลา
    • หมายเหตุ: สำหรับวัตถุประสงค์ของ Rails ทั้ง Timestamp และ DateTime หมายถึงสิ่งเดียวกัน (ใช้ทั้งสองประเภทเพื่อเก็บทั้งวันที่และเวลา) สำหรับคำอธิบาย TL; DR ของสาเหตุที่มีอยู่ทั้งสองให้อ่านย่อหน้าด้านล่าง

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

หมายเหตุ: การปรากฏตัวของทั้งสอง:DateTimeและ:Timestampจากสิ่งที่ฉันสามารถหาได้ถูกรวมไว้โดย Rails ส่วนใหญ่เพื่อความเข้ากันได้กับระบบฐานข้อมูล ตัวอย่างเช่นTIMESTAMPประเภทข้อมูลของ MySQL จะถูกจัดเก็บเป็นเวลาประทับ unix ช่วงที่ถูกต้องไปจาก 1970 ถึง 2038 และเวลาจะถูกเก็บไว้เป็นจำนวนวินาทีที่ผ่านไปตั้งแต่ยุคสุดท้ายซึ่งเป็นมาตรฐานที่คาดคะเน แต่ในทางปฏิบัติอาจแตกต่างจากระบบสู่ระบบ เมื่อตระหนักว่าเวลาสัมพัทธ์ไม่ใช่สิ่งที่ดีที่จะมีในฐานข้อมูล MySQL จึงแนะนำDATETIMEประเภทข้อมูลที่เก็บทุกหลักในปีเดือนวันชั่วโมงนาทีและวินาทีในราคาที่เพิ่มขึ้น TIMESTAMPประเภทข้อมูลถูกเก็บไว้เพื่อความเข้ากันได้ย้อนหลัง ระบบฐานข้อมูลอื่น ๆ ต้องผ่านวิวัฒนาการที่คล้ายกัน Rails ยอมรับว่ามีหลายมาตรฐานอยู่และมอบอินเทอร์เฟซให้กับทั้งสอง อย่างไรก็ตาม Rails ActiveRecord มีค่าเริ่มต้นทั้งวันที่:Timestampและ:DateTimeเวลา UTC เก็บไว้ใน MySql DATETIMEดังนั้นจึงไม่มีความแตกต่างในการทำงานของโปรแกรมเมอร์ Rails สิ่งเหล่านี้มีอยู่เพื่อให้ผู้ใช้ที่ต้องการแยกความแตกต่างระหว่างทั้งสองสามารถทำได้ (สำหรับคำอธิบายเชิงลึกเพิ่มเติมดูคำตอบ SO นี้ )


21
นั่นคือการเขียนที่ยอดเยี่ยม @aguazales ดูเหมือนว่าการกำกับดูแลขนาดใหญ่ที่เอกสารของ Rails ไม่มีอะไรเช่นนี้
Birchmeier

ขอบคุณ :) และฉันเห็นด้วยอย่างยิ่ง ActiveRecord และประเภทข้อมูลนั้นสำคัญกับ Rails, idk ว่าทำไมเอกสารนี้ไม่ใช่เอกสารมาตรฐาน
aguazales

2
ข้อความไม่ได้มีความยาวไม่ จำกัด - ใน MySQL มีข้อ จำกัด ประมาณ 16kb มีประเภทฐานข้อมูล MEDIUMTEXT และ LONGTEXT หากคุณต้องการมากกว่า 16kb
Haegin

3
นอกจากนี้ยังเป็นแหล่งที่ดีRails ชนิดข้อมูล Migration - MySql - PostgreSQL - SQLite ฉันรู้ว่ามันเป็นฐานข้อมูลที่เฉพาะเจาะจง แต่การรู้ว่าการใช้งานจริงยังคงมีประโยชน์เมื่อทำความเข้าใจกับฐานข้อมูลทางรถไฟ
เนท

1
ฉันไม่สามารถมั่นใจได้ 100% แต่ผมคิดว่าทรัพยากรของเนทได้รับการโพสต์ใหม่ที่นี่
aguazales

10

จากรหัสที่มาสาขา Rails ต้นแบบฉันพบ:

abstract mysql_adapter

#activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb

  NATIVE_DATABASE_TYPES = {
    primary_key: "bigint auto_increment PRIMARY KEY",
    string:      { name: "varchar", limit: 255 },
    text:        { name: "text", limit: 65535 },
    integer:     { name: "int", limit: 4 },
    float:       { name: "float" },
    decimal:     { name: "decimal" },
    datetime:    { name: "datetime" },
    timestamp:   { name: "timestamp" },
    time:        { name: "time" },
    date:        { name: "date" },
    binary:      { name: "blob", limit: 65535 },
    boolean:     { name: "tinyint", limit: 1 },
    json:        { name: "json" },
  }

  # Maps logical Rails types to MySQL-specific data types.
  def type_to_sql(type, limit = nil, precision = nil, scale = nil, unsigned = nil)
    sql = case type.to_s
    when 'integer'
      integer_to_sql(limit)
    when 'text'
      text_to_sql(limit)
    when 'blob'
      binary_to_sql(limit)
    when 'binary'
      if (0..0xfff) === limit
        "varbinary(#{limit})"
      else
        binary_to_sql(limit)
      end
    else
      super(type, limit, precision, scale)
    end

    sql << ' unsigned' if unsigned && type != :primary_key
    sql
  end    

# and integer ...

  def integer_to_sql(limit) # :nodoc:
    case limit
    when 1; 'tinyint'
    when 2; 'smallint'
    when 3; 'mediumint'
    when nil, 4; 'int'
    when 5..8; 'bigint'
    else raise(ActiveRecordError, "No integer type has byte size #{limit}")
    end
  end

 # and text ..

  def text_to_sql(limit) # :nodoc:
    case limit
    when 0..0xff;               'tinytext'
    when nil, 0x100..0xffff;    'text'
    when 0x10000..0xffffff;     'mediumtext'
    when 0x1000000..0xffffffff; 'longtext'
    else raise(ActiveRecordError, "No text type has byte length #{limit}")
    end
  end

# and binary ...

    def binary_to_sql(limit) # :nodoc:
      case limit
      when 0..0xff;               "tinyblob"
      when nil, 0x100..0xffff;    "blob"
      when 0x10000..0xffffff;     "mediumblob"
      when 0x1000000..0xffffffff; "longblob"
      else raise(ActiveRecordError, "No binary type has byte length #{limit}")
      end
    end

superในtype_to_sqlวิธีการ

#activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
  def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
    type = type.to_sym if type
    if native = native_database_types[type]
      column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup

      if type == :decimal # ignore limit, use precision and scale
        scale ||= native[:scale]

        if precision ||= native[:precision]
          if scale
            column_type_sql << "(#{precision},#{scale})"
          else
            column_type_sql << "(#{precision})"
          end
        elsif scale
          raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale is specified"
        end

      elsif [:datetime, :time].include?(type) && precision ||= native[:precision]
        if (0..6) === precision
          column_type_sql << "(#{precision})"
        else
          raise(ActiveRecordError, "No #{native[:name]} type has precision of #{precision}. The allowed range of precision is from 0 to 6")
        end
      elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
        column_type_sql << "(#{limit})"
      end

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