Design Pattern for Custom Fields in Relational Database

前端 未结 4 632
礼貌的吻别
礼貌的吻别 2020-12-08 17:16

I have assigned a task to create (relatively) simple reporting system. In these system, user will be shown a table result of report. A table has some fields and each field g

4条回答
  •  醉话见心
    2020-12-08 17:55

    Avoid stringly-typed data by replacing VALUE with NUMBER_VALUE, DATE_VALUE, STRING_VALUE. Those three types are good enough most of the time. You can add XMLTYPE and other fancy columns later if they're needed. And for Oracle, use VARCHAR2 instead of CHAR to conserve space.

    Always try to store values as the correct type. Native data types are faster, smaller, easier to use, and safer.

    Oracle has a generic data type system (ANYTYPE, ANYDATA, and ANYDATASET), but those types are difficult to use and should be avoided in most cases.

    Architects often think using a single field for all data makes things easier. It makes it easier to generate pretty pictures of the data model but it makes everything else more difficult. Consider these issues:

    1. You cannot do anything interesting with data without knowing the type. Even to display data it's useful to know the type to justify the text. In 99.9% of all use cases it will be obvious to the user which of the 3 columns is relevant.
    2. Developing type-safe queries against stringly-typed data is painful. For example, let's say you want to find "Date of Birth" for people born in this millennium:

      select *
      from ReportFieldValue
      join ReportField
          on ReportFieldValue.ReportFieldid = ReportField.id
      where ReportField.name = 'Date of Birth'
          and to_date(value, 'YYYY-MM-DD') > date '2000-01-01'
      

      Can you spot the bug? The above query is dangerous, even if you stored the date in the correct format, and very few developers know how to properly fix it. Oracle has optimizations that make it difficult to force a specific order of operations. You'll need a query like this to be safe:

      select *
      from
      (
          select ReportFieldValue.*, ReportField.*
              --ROWNUM ensures type safe by preventing view merging and predicate pushing.
              ,rownum
          from ReportFieldValue
          join ReportField
              on ReportFieldValue.ReportFieldid = ReportField.id
          where ReportField.name = 'Date of Birth'
      )
      where to_date(value, 'YYYY-MM-DD') > date '2000-01-01';
      

      You don't want to have to tell every developer to write their queries that way.

提交回复
热议问题