views:

743

answers:

4

Hello

I am trying to create a check constraint on an access (jet?) table.

So, I open the .mdb file with access, go into queries->create query in design view, type esc, then menu->view->query and finally type

create table X ( a number, check (a > 20) )

but access thinks that I have a "syntax error in field definition". However, I don't think so. Therefore my question: is it possible to create a check constraint with access. If so: how.

Additionally, I'd like to create the constraint with dao/vba, not on the GUI. Is that possible?

And lastly, on a slightly related note: how do you enter sql statements into access. I can't imagine that I have to use the queries->design view->query->view route in order to do that. I am used to Oracle's SQL*Plus, which I like very much, and I'd hope there's something similar for access as well.

Thanks for any input Rene

+1  A: 

There is Validation rule on a column. You can use VB for Access. no SQL*Plus here... You can always use SQL Express as a data source - with all the benefits of real sql server and use access only as a front.

Dani
ms-access->Table->Design View->Validation Rule . set to >20. Don't think you can do it via Data Definition Language e.g. Create Table
heferav
@heferav: yes, can be done with SQL DDL. You need to be in ANSI-92 Query Mode, either using the Access UI or OLE DB code (e.g. ADO classic in VBA).
onedaywhen
accept @onedaywhen's superior knowledge on ADO (which I tend to avoid like a barge pole).
heferav
+2  A: 

Here are some notes.

You can create a Pass-Through query for Oracle (Select menu "Query" > "SQL Specific" > "Pass-Through")

Since Access 2003, you can select SQL Server Compatible Syntax (ANSI 92) (http://office.microsoft.com/en-us/access/HA010345621033.aspx)

A validation rule with VBA / DAO

''Reference: Microsoft DAO x.x Object Library

Dim tdf As TableDef
Dim db As Database

Set db = CurrentDb

Set tdf = db.TableDefs("Table1")

tdf.Fields("aDouble").ValidationRule = "<10"
tdf.Fields("aDouble").ValidationText = "Must be less than 10"

Constraints with ADO / VBA. See Intermediate Microsoft Jet SQL for Access 2000

''Reference: Microsoft ADO Ext. x.x for DDL and Security

Dim cn As ADODB.Connection 'For action queries
Dim rs As ADODB.Recordset  'For select queries
Dim s As String
Dim RecordsAffected As Long

Set cn = CurrentProject.Connection

''You can store sql in a table
s = DLookup("SQLText", "sysSQL", "ObjectName='q1'")
''Result: CREATE TABLE tblCreditLimit (LIMIT DOUBLE)
cn.Execute s, RecordsAffected
Debug.Print RecordsAffected

''You can run queries from VBA
s = "INSERT INTO tblCreditLimit VALUES (100)"
cn.Execute s, RecordsAffected
Debug.Print RecordsAffected

s = "CREATE TABLE tblCustomers (CustomerID COUNTER, CustomerName Text(50))"
cn.Execute s, RecordsAffected
Debug.Print RecordsAffected

s = "INSERT INTO tblCustomers VALUES (1, 'ABC Co')"
cn.Execute s, RecordsAffected
Debug.Print RecordsAffected

s = "ALTER TABLE tblCustomers " _
   & "ADD COLUMN CustomerLimit DOUBLE"
cn.Execute s, RecordsAffected
Debug.Print RecordsAffected

''You can add contraints using ADO like so:
s = "ALTER TABLE tblCustomers " _
   & "ADD CONSTRAINT LimitRule " _
   & "CHECK (CustomerLimit <= (SELECT LIMIT " _
   & "FROM tblCreditLimit))"
cn.Execute s, RecordsAffected
Debug.Print RecordsAffected

s = "UPDATE tblCustomers " _
   & "SET CustomerLimit = 200 " _
   & "WHERE CustomerID = 1"
''Error occurs here
cn.Execute s, RecordsAffected

s = "UPDATE tblCustomers " _
   & "SET CustomerLimit = 90 " _
   & "WHERE CustomerID = 1"
cn.Execute s, RecordsAffected
Debug.Print RecordsAffected

''Clean up
''You cannot do this through the database window,
''because of the constraint.
s = "ALTER TABLE tblCustomers DROP CONSTRAINT LimitRule "
cn.Execute s, RecordsAffected
Debug.Print RecordsAffected

s = "DROP TABLE tblCustomers "
cn.Execute s, RecordsAffected
Debug.Print RecordsAffected

s = "DROP TABLE tblCreditLimit "
cn.Execute s, RecordsAffected
Debug.Print RecordsAffected
Remou
You need a CHECK constraint on your table 'tblCreditLimit' to ensure there is never more than one row, otherwise you will get an error when your CHECK constraint 'LimitRule' is tested.
onedaywhen
...and due to the semantic of CHECK constraints it's probably best to avoid referencing more than one table in the same CHECK constraint. The rule you are using is more suited to an ASSERTION which the Access Database Engine does not support ;)
onedaywhen
+1  A: 

To do this in Access, you need to first open the interface into ANSI-92 Query Mode. I've tested your SQL DDL code: it works fine and creates a column of type FLOAT (Double).

Is is not possible to do this using DAO but you can use ADO. Long story short: CHECK constraints were introduced into the engine in the Jet 4.0 era when the Access Team were favouring ADO. With effect from Access2007, the Access Team are back to favouring DAO but have yet to plug the Jet 4.0 'holes' in DAO. So for the majority of Jet 4.0 -only functionality (compressible data types, fixed-length text data types, fast foreign keys, etc) you need to use ADO.

onedaywhen
+1 for a very informative answer.
David-W-Fenton
Actually, I'm wondering about the statement that "check constraints were introduced...in Jet 4" -- table-level and field-level validation rules have always existed in Access (at least from Jet 2). Now, whether there was DDL for creating/altering them is a different issue, and it might be that all that happened with the release of Jet 4 was the addition of DDL support consistent with other databases. You can certainly create them in DAO using the DAO object model (not executing DDL statements).
David-W-Fenton
@David W. Fenton: "it might be that all that happened with the release of Jet 4 was the addition of DDL support" -- Not so. The name 'Table Validation Rule' is misleading; 'Row Validation Rule' would be better because it only applies to the current row. A CHECK constraint, however, can reference values in other rows in the same table and even other tables...
onedaywhen
Consider the oft-used 'temporal database' pattern i.e. a start_date and end_date DATETIME pair of columns on the row to model a period. Alethic business rules require you to ensure that end_date does not occur before start_date, which can indeed be archived using a Table Validation Rule. However, for your 'sequenced' key you need to ensure periods for the same non-sequenced key do not overlap, which cannot be achieved without using a CHECK constraint... most easily achieved by referencing a 'Calendar' auxiliary table.
onedaywhen
Another point about CHECK vs Validation Rules: you can only define one Validation Rule per column/table so you have to combine all rules into one uber rule. There's no limit on CHECK constraints giving you greater rule granularity meaning you can give better feedback to users on how to fix the data i.e. test the name of the constraint that bites: start_date__before_1990, start_date__after_2030, start_date__time_must_be_midnight, etc.
onedaywhen
A: 

You can’t use standard ANSI in the query builder UNLESS you set the database as sql ansi compatible. If you do change this setting, then you CAN can use the sql in the query builder as you have. I would not recommend changing this setting for existing databases however.

If you do, you could type in:

CREATE TABLE z1 
       (id int IDENTITY , FirstName CHAR, LastName CHAR, SSN INTEGER ,
check (id < 20),  
constraint Mypk primary key (id) )

In you don’t need to save the sql in the query builder, and just want to type in the sql, then simply whack ctrl-g to get the access command line prompt, and you can then type in:

currentproject.Connection.Execute "CREATE TABLE
    z1(id int IDENTITY , FirstName CHAR, LastName CHAR, SSN INTEGER ,
    check (id < 20),
    constraint Mypk primary key (id) )"

The above would be typed on one line. So, you can use the command line prompt if you want..

Albert D. Kallal