| The SQLite engine compiled
          into the SQLite COM component is type-less. This means that it will
          permit you put any value into any column except a few special cases
          discussed further. This is true also about the size of the value - for
          instance on Jet, MS SQL server, MySQL and other DB-s you will receive
          error if you attempt to put a string long 100 characters in a filed
          declared as 50 characters wide. In SQLite it will pass and will be
          recorded correctly. No matter what type is assigned to the column in the table
          declaration the column will accept any other type. If you want to
          enforce some restrictions you will need to do this yourself - from
          outside (in the application's code) or from inside (triggers for
          example). Only few restrictions can be effectively applied in a CREATE
          TABLE statement or an INDEX (see also SQL reference)
          and they are not type oriented - NOT NULL (to disallow null values in
          the column, UNIQUE (to disallow duplicate values) and INTEGER PRIMARY
          KEY will have some more effect but only on one column. So, the only true exception is the INTEGER PRIMARY KEY column
          declaration which makes the column auto increment and forced to
          contain only INTEGER values (32-bit). While the values in such columns
          are managed by the DB engine this has nothing to do with the typing of
          the actual data. How this works without types?(See also the expressions in the
        SQL Reference for detailed description of the type behavior in
        expressions.)
 The trick is that the values are converted to whatever
          is needed only when they occur in statements, but there are only two
          general types supported: TEXT and NUMERIC. In other words any
          expression may return only one of these two types (see the expressions
          for information which expressions generate which type).
           The types of the fetched data. Thus you will be concerned about the types when you fetch data from
          the DB. The SELECT statements return set
          of fields. Part of them may correspond to directly to certain columns
          of the tables involved, others will be result of expressions. The
          result fields that are result of expressions will be NUMERIC or TEXT
          depending on the result of the expression, while the fields that
          correspond to columns directly will be reported as declared (with the
          type name specified in the CREATE TABLE when the table has been
          created). Sometimes this type-less-ness is something desired and
          helpful, but other applications will need some more strict typing for
          some columns at least. SQLite allows you to use the DB engine as you
          prefer with very little efforts from the outside (in the application
          code). So, you can combine both at the level that suits your needs. How
          to deal with the types yourself. There are two directions for
          which this question must be answered separately - writing data
          (INSERT, UPDATE) and reading data (SELECT). In all the sample code
          lines below we will assume that the db variable has been created like Set
          db = Server.CreateObject("newObjects.sqlite.dbutf8") and
          then a database has been opened using db.Open.
          We assume that the tables we use for sample purposes already exist.
           
            Writing data (INSERT, UPDATE) The most convenient way to
            put the data in correct form (from typing point of view) is to use a
            formatting function that will do this. The Sprintf
            method of the StringUtilities
            object is just what you need (it is useful for non-db scenarios
            as well). With it you specify a format string that contains the
            constant parts of the query and escape command sequences where data
            must be put from externally supplied arguments. For example lets
            take an INSERT statement we want to compose: Set su = Server.CreateObject("newObjects.utilctls.StringUtilities")
' Assume the variables arg1,arg2,arg3 are initialized from appropriate
' source. For example arg1 = Request("SomeField") and so on.
str = Sprintf("INSERT INTO T (F1,F2,F3) VALUES (%q,%d,%M);",arg1,arg2,arg3)
Set r = db.Execute(str)
...The Sprintf uses variable argument list. This means you can pass
            as many arguments after the first argument of the function (which is
            the format
            string) as the format string requires. Each %<something>
            sequence in it refers to an argument from the list and the sequence
            specifies how it will be formatted in the output string. See the
            syntax of the %<something> sequences in the format
            specifications for the Sprintf
            method. In the above example %q - means that the arg1 will
            be treated as string and all the ' characters in it will be escaped
            (by doubling them) in SQL safe manner and finally it will be
            enclosed in 'quotes' when inserted instead of %q in the
            output string. The next one %d refers to the next argument (arg2)
            and it will be treated as integer value, the %M refers to the next
            one arg3 and says that it will be treated as double precision value
            which will be formatted with Maximum precision. The Sprintf
            method uses by default . for decimal symbol thus it will generate
            correct SQL numeric representations for the numeric arguments. Also
            the %q and %Q
            escapes help you escape the strings passed to the data base without
            additional efforts. As the above can be combined in one line of
            VBScript code (or translated to one line of JScript code) you need
            only single line to perform all the typing you need no matter that
            the database engine will not enforce types itself. The Sprintf
            method will try to convert the arguments to the types required by
            the escape command (%<something>) that corresponds to it. If
            the conversion fails error will be generated as like another
            database engine will generate if you try to put incompatible value
            type in it. Reading data (SELECT)Numeric types list definition
 In general the data read
            is always textual unless the auto typing mode is set (see AutoType
            property). The Auto Typing
            mode simplifies the conversion tasks you need when reading data, but
            again it is highly customizable and you can tune the data base to
            work in quite different ways depending on the settings you specify
            (see AddNumericType, CountNumericTypes,
            NumericType and the other
            related members). Aside of auto typing mode you have the ParseNumeric
            method. It parses a string that contains a numeric value in SQL
            compatible format (. - for decimal, E or e for exponent if any).
            However it needs additional effort to be applied.  To make it
            easier you can turn on auto
            typing mode after creation of the SQLite COM object. By default
            the following types: NUMERIC, INTEGER, SMALLINT, DATE, TIME, DOUBLE, FLOAT,
            SINGLE, SHORT, LONG, DATETIME, INT, BYTE are
            treated as numeric. If the auto typing mode is turned on when
            packing the result the returned values (the fields in the row
            collections) will be converted to VT_I4 or VT_R8 VARIANT-s if they
            are of one of the above types. I.e. the corresponding elements in
            the row collections will contain VARIANT values of these types and
            the application will be able to use them directly in expressions
            where numbers are needed. When you work with English locale
            settings this may seem a bit stupid work done for nothing, but
            remember that many locales use incompatible numeric formats and the
            returned strings (if auto typing mode is off) will not be recognized
            as numeric values by the most languages (VBScript for example). So
            you need to use one of the both methods - manual usage of
            ParseNumeric or auto typing
            mode if you expect that your application will deal with locales that
            may cause problems. Even if you do not have such plans it is
            recommended - for example many users in non-English speaking
            countries use English as their work language. If it happens that
            such an user attempts to use your application it will fail if his
            locale settings are different and you do not use auto typing or
            ParseNumeric manually. The types treated as numeric can be changed
            to fit your needs. Using the following methods and properties you
            can change that list: AddNumericType,
            RemoveNumericType, CountNumericTypes,
            RemoveAllNumericTypes,
            NumericType(index). This is
            called numeric types list in this documentation .This may be
            useful to keep your database declarations as close as possible to
            syntax compatible with other databases (if for instance another
            version of the application works with another database engine).
           What to do with date/time values? Most database engines
          support some kind of date/time representation formats for date/time
          literal values. This is used by many developers in the queries they
          execute. It is particularly useful if the database is to be maintained
          manually from an SQL console from example. However if the interface
          with the database is through an application it is of little importance
          and all you need to consider is correct functioning of the arithmetic
          functions with date/time values or at least correct ordering if no
          expressions will be used. With SQLite COM you can design you own
          technique, but there is one that is most convenient of all: The
          VT_DATE (vbDate) in COM is in fact double precision floating point
          number that represents the date and the time. So it is always possible
          to convert VT_R8 (vbDouble) value to VT_DATE (vbDate) value and
          reverse without loses. For instance CDate(CDbl(Now)) will be equal to
          Now in VBScript. The implicit conversions wherever they are required
          by the expressions used in the application will always succeed. This
          makes the VT_R8 (vbDouble) numeric type most convenient for usage in
          the database. It will behave perfectly in any arithmetic expressions
          and also will keep the perscision if formatted in the SQL statements
          with maximum precision. When writing data into the db: For
          that purpose you can use the Sprintf method and the %M escape (see the
          format
          specifications) to print the date/time values from the application
          into the SQL statements executed over the database. When fetching
          data from the db: Using ParseNumeric or automatically (if auto
          typing is on) the values that contain date and/or time values will
          be converted to VT_R8 (vbDouble) which will implicitly convert to DATE
          wherever the expressions need it this way in your application. If auto
          typing is used all you need to do is to make sure your numeric types
          list (see above) contains the type names you use to indicate date
          and/or time values. The default configurations assumes DATE and TIME
          type names are used for this purpose. Thus the back-and-forth
          example below: db.AutoType = True
db.AddNumericType = "DATE"
db.Ecxecute("CREATE TABLE T (A DATE);")
Set r = db.Execute("INSERT INTO T (A) VALUES (%M);",Now)
addedID = r.Info
Set r = db.Execute("SELECT A FROM T WHERE OID=" & addedID)
Response.Write "Today is: " & r(1)("A")Will display the same as simple Response.Write "Today is:
          " & Now The DATE type is good for both date and time and
          only date or only time values. The arithmetic operations will produce
          correct results. So, only one date/time type is enough and you can
          remove one of the default date/time type names if you do not want to
          use it.  |