Set limit on number of records that can have a particular field value

romeluc

Registered User.
Local time
Today, 05:26
Joined
Aug 16, 2014
Messages
13
I need help building a validation expression that concerns four of my fields:

Country | Text
Centr | Boolean
Centr limit | Integer
Apply | Boolean

The number of records that have the same country, AND Centr=TRUE, AND Apply=TRUE, should not exceed the Centr limit value.

I am a complete beginner and designing my first data base. Therefore i would appreciate the help.
 
Last edited:
It would be better and clearer if you could tell us WHAT you are trying to do in plain English.
 
It would be better and clearer if you could tell us WHAT you are trying to do in plain English.
sure. I made the edits to my post.
 
The number of records that have the same country, AND Centr=TRUE, AND Apply=TRUE, should not exceed the Centr limit value.

From that explanation your tables aren't structured properly. Centr limit shouldn't be in that table. If its a limit on the entire table, you dont store the limit amount within every single record in the table. You need a new table to hold that value.

Then to answer JHB's question, this will have to be done with VBA in a form. You would set it up so people input data into an unbound form, then when they click the 'Submit' button your form first validates the data (it doesn't exceed the limit) then if its under limit INSERTS the data into your table, if its over, you show a message box saying so.

Again, a new table to hold the limit, then start reading up on how to build forms.
 
From that explanation your tables aren't structured properly. Centr limit shouldn't be in that table. If its a limit on the entire table, you dont store the limit amount within every single record in the table. You need a new table to hold that value.

Then to answer JHB's question, this will have to be done with VBA in a form. You would set it up so people input data into an unbound form, then when they click the 'Submit' button your form first validates the data (it doesn't exceed the limit) then if its under limit INSERTS the data into your table, if its over, you show a message box saying so.

Again, a new table to hold the limit, then start reading up on how to build forms.

Ok. Can't I apply the validation to the table instead of the form. I made a form for another table before so I have to learn VBA next.

What about a macro? I tried this in a macro:
Code:
if 
Count([Universities]![Country] & [Universities]![Centralized]=True & [Universities]![Apply?]=True)<[Universities]![Cent Limit]
Then

SetValue
    Item = [Universities]![Apply?] 
    Expression = False
When I run it, I get an error saying "Microsoft Access cannot find the name 'Universities' you entered in the expression," even though i entered it from the expression builder.


Also, I learned about data macros and tried to use it on my table but there was no Count() function.
 
Last edited:
Can't I apply the validation to the table instead of the form.

No. Such a thing exists in other databases (triggers), but not in Access. You have to enforce this type of validation with a form. I'm sure you can create validation code in a macro that you attach to a form. But my advice is to do it with VBA. Macros are VBA lite, and your issue is sort of complex so you might as well go the extra eighth of a mile and just learn VBA instead of trying it via a macro.

Count is a SQL function (http://www.w3schools.com/sql/sql_func_count.asp), not a VBA function. In this countext you would want the DCount function (http://www.w3schools.com/sql/sql_func_count.asp)
 
No. Such a thing exists in other databases (triggers), but not in Access. You have to enforce this type of validation with a form. I'm sure you can create validation code in a macro that you attach to a form. But my advice is to do it with VBA. Macros are VBA lite, and your issue is sort of complex so you might as well go the extra eighth of a mile and just learn VBA instead of trying it via a macro.


Thanks for the info. I am now attempting to write the code. This is what I have so far:
Code:
Option Compare Database
Option Explicit

Sub MyCodeRoutine()
    
    Dim count As Integer
    
    count = DCount("*", "Universities", "Centralized = True And Apply = True")
    MsgBox count
    
End Sub
I had to change the Apply? field to Apply because a '?' caused an error. What I need to do next is find a way to add the country condition. I need the records to have the same country field value in order to be counted. Can this be done by just adding an additional criteria in Dcount?

I am trying, instead, to construct a For statement but I'm struggling with the syntax. How to say:

for each country value in the country field (it is a combo box),
count = DCount("*", "Universities", "Country = the country value And Centralized = True And Apply = True")


Btw, I also intend to change my database design as you suggested before but I want to get this validation functionality to work first.
 
Last edited:
Can this be done by just adding an additional criteria in Dcount?

Yes. You already have 2 criteria, just keep adding ANDs to it to add more.

I don't understand what you are trying to do with your combo box. Instead of a looping DCount, you should use a query. Why are you looping through everything in the combo box? You should only be concerned with the one selected.
 
Yes. You already have 2 criteria, just keep adding ANDs to it to add more.

I don't understand what you are trying to do with your combo box. Instead of a looping DCount, you should use a query. Why are you looping through everything in the combo box? You should only be concerned with the one selected.

I wanted to make sure that each country available does not violate the rule ( number of records where both Centralized = True And Apply = True). I'm not sure who to do this by adding another AND.

If I can find out which record is modified in the table, then I can get the Country value (with Dlookup()) and assign it to a variable. Is this what you meant? Maybe this is where form events comes in.

I want the rules to hold if the records are modified in the table. I need to see all the data before setting the Apply for any record. The form should not have Apply on it.
 
You can implement the constraint at table level using a CHECK constraint. Something like the following will work:

Code:
ALTER TABLE tblData ADD 
   CONSTRAINT country_limit 
      CHECK ( 
             NOT EXISTS
                      (
                              SELECT tblData.Country, Count(tblData.ID) AS CountOfID
                              FROM tblData
                              WHERE ((tblData.Centr)=True) AND (tblData.Apply)=True
                              GROUP BY tblData.Country
                              HAVING Count(tblData.ID)>=5
                       )
            );

You can change the 5 to a lookup value (subquery or D function I guess).

There are a couple of notes worth mentioning:

  • You won't be able to see the CHECK constraint once you have implemented. So you will only know it is there by virtue of the fact you implemented it. And of course the fact that it does constrain.
  • You can DROP the constraint if you want to get rid of it
  • You need to set your database SQL mode to ANSI 92 when you create the database - at least for later versions of Access

Like other table level constraints, the error message is not terribly user friendly - something like "one or more rules are violated by the validation rule country_limit...". So even though you enter the table level constraint, you still might want to implement some code to make a nice front end experience for the user.

If this is a mission critical database where there are multiple people designing front ends then implementing the constraint at table level is a must. But if this is your first database then I would focus on doing this via the form (recognising that if someone gets direct access to the table then they can bypass the constraint).

hth
Chris
 
You can implement the constraint at table level using a CHECK constraint. Something like the following will work:

Code:
ALTER TABLE tblData ADD 
   CONSTRAINT country_limit 
      CHECK ( 
             NOT EXISTS
                      (
                              SELECT tblData.Country, Count(tblData.ID) AS CountOfID
                              FROM tblData
                              WHERE ((tblData.Centr)=True) AND (tblData.Apply)=True
                              GROUP BY tblData.Country
                              HAVING Count(tblData.ID)>=5
                       )
            );
You can change the 5 to a lookup value (subquery or D function I guess).

There are a couple of notes worth mentioning:

  • You won't be able to see the CHECK constraint once you have implemented. So you will only know it is there by virtue of the fact you implemented it. And of course the fact that it does constrain.
  • You can DROP the constraint if you want to get rid of it
  • You need to set your database SQL mode to ANSI 92 when you create the database - at least for later versions of Access

Like other table level constraints, the error message is not terribly user friendly - something like "one or more rules are violated by the validation rule country_limit...". So even though you enter the table level constraint, you still might want to implement some code to make a nice front end experience for the user.

If this is a mission critical database where there are multiple people designing front ends then implementing the constraint at table level is a must. But if this is your first database then I would focus on doing this via the form (recognising that if someone gets direct access to the table then they can bypass the constraint).

hth
Chris

Should I put the code in VBA editor? I changed to ANSI 92 in Access options, but I'm getting syntax errors with the code.
 
Should I put the code in VBA editor? I changed to ANSI 92 in Access options, but I'm getting syntax errors with the code.

No. Just open a new query and then switch to SQL view. Copy and paste into the SQL window. Save and run.

Obviously you need to change the code to reflect the name of the table you are using.

But as I said, if you are new to database design you maybe go down the form route. You may want to fully test this before being sure that this is for you.

Also research ANSI 92 in Access because it changes what is allowed in SQL syntax.

Chris
 
No. Just open a new query and then switch to SQL view. Copy and paste into the SQL window. Save and run.

Obviously you need to change the code to reflect the name of the table you are using.

But as I said, if you are new to database design you maybe go down the form route. You may want to fully test this before being sure that this is for you.

Also research ANSI 92 in Access because it changes what is allowed in SQL syntax.

Chris

I modified your code to:
Code:
ALTER TABLE Universities ADD
   CONSTRAINT Cent_limit  
      CHECK ( 
             NOT EXISTS
                      (
                              SELECT Universities.Country, Count(Universities.ID) AS CountOfID
                              FROM Universities 
                              WHERE ((Universities.Centralized)=True) AND (Universities.Apply)=True
                              GROUP BY Universities.Country
                              HAVING Count(Universities.ID)>=5
                       )
            );

But it is giving me this error:

Code:
Syntax error in CHECK CONSTRAINT clause. (Error 3765) 

This error occurs when using SQL DLL to define a CHECK constraint. It occurs when the search condition (SELECT statement) in the CHECK clause references an invalid table or column name.

My table name is Universities and that is what I used in the code.I'm not sure about Universities.ID. I don't have a field called ID.
 
ID was just an example primary key field. You could try:

Code:
ALTER TABLE Universities ADD
   CONSTRAINT Cent_limit  
      CHECK ( 
             NOT EXISTS
                      (
                              SELECT Universities.Country, Count(Universities.[COLOR="Red"]Country) AS CountOfCountry [/COLOR]
                              FROM Universities 
                              WHERE ((Universities.Centralized)=True) AND (Universities.Apply)=True
                              GROUP BY Universities.Country
                              HAVING Count(Universities.[COLOR="Red"]Country[/COLOR])>=5
                       )
            );
 
ID was just an example primary key field. You could try:

Code:
ALTER TABLE Universities ADD
   CONSTRAINT Cent_limit  
      CHECK ( 
             NOT EXISTS
                      (
                              SELECT Universities.Country, Count(Universities.[COLOR=Red]Country) AS CountOfCountry [/COLOR]
                              FROM Universities 
                              WHERE ((Universities.Centralized)=True) AND (Universities.Apply)=True
                              GROUP BY Universities.Country
                              HAVING Count(Universities.[COLOR=Red]Country[/COLOR])>=5
                       )
            );


Ok, now it ran. But when I go to my table, it doesn't let me make changes or save it. Gives me an error every time. I tried deleting the query but that didn't stop it.

I don't have a key field in that table, btw.
 
You can remove the constraint using this in a new query:

ALTER TABLE Universities Drop CONSTRAINT Cent_limit


I suspect you already have violations in your table so when you add the constraint it won't let you do anything because you always have a violation.

So delete the constraint (above) then make sure you have no violations. The add the constraint again.

I hope you are doing this in a test environment so you don't mess up your live data.

Chris
 
You can remove the constraint using this in a new query:

ALTER TABLE Universities Drop CONSTRAINT Cent_limit


I suspect you already have violations in your table so when you add the constraint it won't let you do anything because you always have a violation.

So delete the constraint (above) then make sure you have no violations. The add the constraint again.

I hope you are doing this in a test environment so you don't mess up your live data.

Chris

This is wonderful. Thanks.

Now I need to replace the 5 with the cntr_limit field value stored in another table (called Constants) that corresponds to the same country. Should I use something like:
Code:
SELECT Constants.Country AS Expr1
FROM Constants
not sure what I should do for the country.
 
So now your constraint needs to look something like this:
Code:
ALTER TABLE Universities ADD
   CONSTRAINT Cent_limit  
      CHECK ( 
             NOT EXISTS
                      (
                              SELECT Universities.Country, Count(Universities.Country) AS CountOfCountry 
                              FROM Universities 
                              WHERE ((Universities.Centralized)=True) AND (Universities.Apply)=True
                              GROUP BY Universities.Country
                              HAVING Count(Universities.Country)>=
                                     (
                                       SELECT max(Constants.cntr_limit)
                                       FROM Constants
                                       WHERE Constants.Country=Universities.Country;
                                     )
                       )
            );

You will need the DROP the constraint then ADD it again.
 
Last edited:
So now your constraint needs to look something like this:
Code:
ALTER TABLE Universities ADD
   CONSTRAINT Cent_limit  
      CHECK ( 
             NOT EXISTS
                      (
                              SELECT Universities.Country, Count(Universities.Country) AS CountOfCountry 
                              FROM Universities 
                              WHERE ((Universities.Centralized)=True) AND (Universities.Apply)=True
                              GROUP BY Universities.Country
                              HAVING Count(Universities.Country)>=
                                     (
                                       SELECT max(Constants.cntr_limit)
                                       FROM Constants
                                       WHERE Constants.Country=Universities.Country;
                                     )
                       )
            );
You will need the DROP the constraint then ADD it again.

Thank you very much. This is what I need. I am going to pick up a book and attempt to learn some SQL. I think I will need it for the next task.
 

Users who are viewing this thread

Back
Top Bottom