I am trying to create a validation rule but using SQL in Access. I am very new to this. I know how to do it in regular Access design view, but don't know how to do it when using the create table command. So far I have,
CREATE TABLE CUSTOMERS
(
CustomerName TEXT (20),
Gender TEXT (10),
FavoriteFood TEXT (20)
);
Would like to add a validation rule to gender for just male/female/notknown.
A field's Validation Rule is a DAO.TableDef property which can't be created using Access SQL.
If you want to use Access SQL for something similar, use a CHECK CONSTRAINT. This statement will limit Gender values to male, female, or unknown.
CREATE TABLE CUSTOMERS
(
CustomerName TEXT (20),
Gender TEXT (10) NOT NULL,
FavoriteFood TEXT (20),
CONSTRAINT allowed_genders CHECK
(
Gender IN ('male','female','unknown')
)
);
Note a CHECK CONSTRAINT can only be used in Access SQL when executed from ADO. I executed that statement with CurrentProject.Connection.Execute, which is an ADO method.
Some consequences of this approach may make it unacceptable to you ...
The constraint is not visible in table Design View.
When the constraint is violated, the error message does not appear until you attempt to save the record.
And the error message is based on the constraint name ... which is not very user-friendly in this case.
Because of the constraint, you can not delete the table from the Access UI; you would have to first execute DROP CONSTRAINT allowed_genders and then delete the table, or execute DROP TABLE CUSTOMERS which will discard both the table and constraint at the same time.
You might prefer to create a simpler version of the table and then set the Validation Rule with DAO.
Dim db As DAO.Database
Dim tdf As DAO.TableDef
Set db = CurrentDb
Set tdf = db.TableDefs("CUSTOMERS")
tdf.Fields("Gender").ValidationRule = "IN ('male','female','unknown')"
tdf.Fields("Gender").ValidationText = "Gender must be male, female, or unknown"
Notes:
The DAO methods allow you to also include a user-friendly Validation Text message.
When the Validation Rule is violated, Access will display the error message as soon as you attempt to move to the next field.
Finally yet another approach would be to create a lookup table which contains your allowed Gender values, make CUSTOMERS.Gender a foreign key to that lookup field, and enforce referential integrity.
Any of those 3 approaches might fit your situation; choose whichever seems to fit best. :-)
Related
I'm new to SQL and try to get some handy knowledge from the book "SQL for Microsoft Access 2nd Edition" published in 2008.
In chapter 3, keyword ON UPDATE CASCADE ON DELETE CASCADE are introduced. I tried to run the statements with the keywords in MS Access 2013's SQL view. There is an error message saying
"Syntax error in CONSTRAINT clause."
The statements work perfectly without ON UPDATE CASCADE ON DELETE CASCADE.
The note in the book explain the keywords don't work on the version before SQL-92. I guess Access 2013 is way after SQL-92.
Can anyone explain to me why the keywords don't work?
below is the statements (ON UPDATE CASCADE ON DELETE CASCADE is at the end):
CREATE TABLE tblManufacturers
(
ManufacturerID INTEGER CONSTRAINT ManfID PRIMARY KEY,
ToyID INTEGER NOT NULL,
CompanyName CHAR (50) NOT NULL,
Address CHAR (50) NOT NULL,
City CHAR (20) NOT NULL,
State CHAR (2) NOT NULL,
PostalCode CHAR (5) NOT NULL,
AreaCode CHAR (3) NOT NULL,
PhoneNumber CHAR (8) NOT NULL UNIQUE,
CONSTRAINT ToyFk FOREIGN KEY (ToyID) REFERENCES tblToys (ToyID)
ON UPDATE CASCADE
ON DELETE CASCADE
);
Those keywords don't work because DAO doesn't support them. Built-in query builder also uses DAO. If you want to create table using CASCADE keywords, it can be done in VBA using ADO only:
CurrentProject.Connection.Execute strSQL
strSQL here contains CREATE TABLE statement
The ON UPDATE CASCADE and ON DELETE CASCADE statements are not supported by Access (see https://msdn.microsoft.com/en-us/library/office/ff836971.aspx).
Regarding the functionality, you should not have a need to use ON UPDATE CASCADE. This constraint means that if you do change a primary key in the master table, the changes propagate to every child table referencing the master table. Changing a primary key is considered a no-go in the SQL world. Is you really must change primary keys (because of some kind of disaster struck), this will be done with a script, lots of backup and extreme care. A primary key is this: a unique (ideally globally), immutable identifier of a row in a table.
The ON DELETE CASCADE means that if you remove a row in the master table, any rows referencing this key in child tables will also be deleted. While this sounds like a lazy shortcut, I would recommend against it and doing this within application logic (there might be a use case where you want to retain records or log them or do something with them instead of blindly erasing them from the database.
I have 3 tables, "Courses"(id, start_date), "Subscriptions"(id, assistant_id, course_id, date) and "Assistants"(id, registration_date).
Subscriptions reference Courses and Assistants with foreign keys as you see.
I need to add CHECK constraint that will prevent to create Subscription record if referenced Courses.start_date is older than referenced Assistants.registration_date. Is there a way to do this in Libre Base?
Table organization could not be changed.
Such a CHECK constraint cannot be created with the default engine. From the HSQLDB 1.8 documentation:
ALTER TABLE <tablename> ADD [CONSTRAINT <constraintname>]
CHECK (<search condition>);
Adds a check constraint to the table. In the current version, a check constraint can reference only the row
being inserted or updated.
This means that commands like the following from TestSelfCheckConstraints.txt produce an error:
/*e*/CREATE TABLE TC6(A CHAR, B CHAR, C CHAR, D INT, CHECK(A IN (SELECT A FROM
TC5)));
So, to perform such a check, you will have to verify it ahead of time (or afterwards) using a query. This could be done for a form by adding a macro in the Events tab. See this post for ideas: https://forum.openoffice.org/en/forum/viewtopic.php?f=20&t=21414.
The default engine is rather old, so for such complex requirements it may be better to set up LibreOffice Base to use a different database engine. For example using MySQL, it is possible to set up a stored procedure trigger to do this kind of checking. See CHECK constraint in MySQL is not working.
So there's a couple problems I'm running into regarding getting this to work.
Here's the function:
CREATE FUNCTION RSO_Affiliation_AdminID_is_Admin_Enforcer
#Admin_ID nvarchar(50)
RETURNS INT
AS
BEGIN
DECLARE #ACCESS nvarchar(50)
SET #ACCESS = (SELECT ACCESS FROM Student WHERE USER_ID = #ADMIN_ID)
IF (#ACCESS LIKE 'Admin')
RETURN 1;
IF (#ACCESS LIKE 'SuperAdmin')
RETURN 1;
RETURN 0;
END
GO
I'm pretty new to SQL and SQL server management studio, so if there's anything generally wrong with the syntax here, that'd be the primary problem, but as far as I've seen, this should work. Essentially, this should be called by a constraint for the RSO_Affiliation table with the new ADMIN_ID as a parameter, it should check it against the Student table, and return 1 if it turns out the Access level for the matching USER_ID is an admin of some kind, return 0 otherwise.
Problem 1 is that I can't seem to find this function in the Object Explorer. Despite saving it over and over, refreshing and reconnecting to the DB multiple times, its absent from all Function folders. It saved to the SQL Management Studio folder in My Documents, but as far as I know, my actual Database doesn't know it exists. I created it as a Scalar-valued Function by the way.
Problem 2 is that I don't know the syntax for what I should type into the RSO_Affiliation -> Check Constraints -> Expression dialog window. From what I've seen from other questions,
dbo.RSO_Affiliation_AdminID_is_Admin_Enforcer(ADMIN_ID) = 1
should work, but it doesn't, probably because again, I don't think my database knows where to look for the function itself.
Any insights?
EDIT
So I finally figured out that to get SMSS to add the function to the DB, you need to test it with the Execute button in the top-left hand corner of the toolbar. I was able to the use it in the constraints menu with the above code no problem, except for one:
It apparently doesn't do anything. Presumably, its called by the constraint with the pending ADMIN_ID, but I can use students with non-admin access levels to create new RSOs. Any ideas why this might be the case?
You can do what you want with foreign key constraints, assuming that user_id is unique in student. This saves the trouble of a user defined function, but the implementation has a couple of gotchas.
First, you need a unique key on students to identify who is admin or super admin:
alter table student add IsAdmin as (case when ACCESS in ('Admin', 'SuperAdmin') then 1 else 0 end);
create unique index unq_Student_IsAdmin on Student(user_id, IsAdmin);
Then, create a foreign key constraint in the table you care about:
alter table t add IsAdmin (1);
alter table t add constraint fk_t_student_isadmin
foreign key (admin_id, IsAdmin) references student(user_id, IsAdmin);
This then guarantees that that the admin_id in the table you are setting up is an admin.
I Am new in stackoverflow and whats worst is I am new to Microsoft Access. My homework
Assume the Part table has been created, but there are no integrity constraints. Create the necessary integrity constraint to ensure that the only allowable values for the Class field are AP, HW, and SG. Ensure that the PartNum field is the primary key and that the PartNum field in the OrderLine table is a foreign key that must match the primary key of the Part table.
So I know how to create this by using Microsoft Access by going to the Validation Rule and add validation for AP, HW, and SG. However, I need to also create the query to show how this is done.
My code:
ALTER TABLE Parts
ADD CONSTRAINT classRule
CHECK IN Class(AP, HW, SG)
;
My textbook has an example which is similar to what I just wrote above. When I run this I get a Constraint error. What am I doing wrong? Also, the foreign key and primary key have already been made so I just need to write the sql query to display my result. Any help is appreciated!
The CHECK clause exists but it's not a particularly good idea to use it because it can create issues in you application.
That being said, your constraint should work but there are a couple things:
You should avoid the use of the word Class as a field name. It's not a reserved word per se, but it's a VBA reserved word and while Access let you create that field, you may encounter strange problems elsewhere later.
As Brian said, you need to use single quotes for string literals in your CHECK
You can't create CONTRAINT with CHECK from the SQL Query Editor in Access, you'll get errors on the CHECK part every time you try.
Instead you need to execute the DDL SQL from VBA: just open the VBA (Alt+F11) then type the following in the Immediate Window (Ctrl-G if you don't see it), then press ENTER:
CurrentProject.Connection.Execute "ALTER TABLE Parts ADD CONSTRAINT ClassRule CHECK (Class IN ('AP', 'HW', 'SG'));"
If you don't get an error, then the constraint was properly executed, otherwise, double check that the syntax is correct, field names, parenthesis are properly balanced, and that the Part table is not open.
You probably want:
ALTER TABLE Parts
ADD CONSTRAINT classRule
CHECK (class in ('AP', 'HW', 'SG'));
There is a space between CONSTRAINT and the name
Put conditions within the () after the CHECK keyword
Put literals within single quotes, as this is what differentiates field names from values
Edit
Although the above is valid syntax, from what I'm reading you may not be able to add a check constraint in Access via writing out the SQL, at least not in the SQL view of query designer.
You can add a check constraint by going to Design View for the table of interest, then on the row representing the column of interest, type the following on the line for "Validation Rule":
in ('AP', 'HW', 'SG')
http://www.databaseskill.com/1942875/
"Note The check constraint statement can only be executed through the Jet OLE DB provider and ADO; it will return an error message if used though the Access SQL View user interface."
Above quote is from the URL I just provided.
I need help with this
I have an MS Access db form which will enable users edit details about a project and the new values entered will be saved to the db table when the save button is clicked I am using the sql UPDATE syntax to do this and my code is similar to below
Private Sub Save_Click()
ltemp = " UPDATE Table1 "
ltemp = ltemp & " SET ClientName = 'ANN' "
ltemp = ltemp & " WHERE ProjectID = 2333 "
CurrentDb.Execute (ltemp)
End Sub
with this code, nothing happened. The code would execute with no errors but the value on the table wouldnt change.
I tried the code
DoCmd.RunSQL " UPDATE Table1 SET ClientName = 'ANN' WHERE ProjectID = 2333"
with this i got a long error message which indicated that the records couldnt be updated due to key violation. The problem is that the field 'ClientName' is not the primary key, although it is linked (in a relationship) to the primary key of another table.
both codes work to update other fields except this one which is in a relationship with the primary key of another table.
Obviously there is no record in your 'client' table with the 'ANN' id, so it cannot be set as a valid value for the corresponding\foreign key field in your updated table.
currentDb.execute instruction will not return any error message (not like the 'DoCommand' one) because it's not supposed to, as long as the syntax is correct (see below). You could try to use the currentDb.RecordsAffected to check if any record was changed by your instruction. Check parameters available for the execute method for further details.
Access Help:
"In a Microsoft Jet workspace, if you provide a syntactically correct SQL statement and have the appropriate permissions, the Execute method won't fail — even if not a single row can be modified or deleted. Therefore, always use the dbFailOnError option when using the Execute method to run an update or delete query. This option generates a run-time error and rolls back all successful changes if any of the records affected are locked and can't be updated or deleted."
You are attempting to violate the referential integrity set up on your database.
As you've noted, there is another table, which will look something like this:
CREATE TABLE Client
(
ClientName VARCHAR(100),
... other client fields here
);
And there is a FOREIGN KEY setup between columns Table1.ClientName and Client.ClientName.
To avoid this, either:
INSERT a client with the name ANN into the other table
DROP the foreign key constraint on Table1.ClientName if you intend to violate the constraint (but note that joins may fail when the client is missing)
Change the design and start using surrogate keys, such as ClientID and referencing the Surrogate key in your other tables (instead of 'natural' keys like Client Name). This way, clients can get married, change their names etc and your database won't break :)