Database Design: Defining Access Control - database

An application I am developing needs to provide access to data based on a list of cities defined for each client. A client can have:
access to all cities in a country OR
access to all cities in a state / region OR
access to select cities in any state
or country.
What would be the best way to define this in the database (if the db has a Country table, State / Region table, City table and a Client table)?
Clarification:
(A simplified view of the tables with only the essential columns pertaining to this question).
Country table -
idCountry | Name
State table -
idState | idCountry | Name
City table -
idCity | idState | Name
Client table -
idClient | Name

You could to create a Location self related table (Id, Name, ParentLocation) and a AccessControl table (ClientId, LocationId). When a client is related to a location, you could grant access to all location below it. Some examples:
ID Name Parent
-------------------
1 World NULL -- Need to represent all countries
2 Brazil 1 -- A country
3 São Paulo 2 -- A state
4 São Paulo 3 -- A city
If you want to stick your current model, maybe a table like (ClientId, CountryId nullable, StateId nullable, CityId nullable). This way you could define your security access as your definition, but would need to deal with nullable fields.

Related

Can I perform conditional DynamoDB calls in a single call?

Lets say I have a table that stores user data. It stores 2 types of data - a UserId (partition key) with attributes (json blob). The other type is a reference to the UserId, based off of values within the attributes, for example, here would be 3 rows of the table:
pk attributes userId
5 | { email: example#example.com, tel: 123456789 } | null
email/example#example.com | null | 5
phone/123456789 | null | 5
This is so I am able to query directly off of values to obtain attributes, without needing to do a scan and filter (a very compute intensive operation on large tables).
My question is: Can I, in a single query, do something like getByPartitionKey(email/example#example.com), obtain the userId, and then use that userID to query for the whole attributes document, without doing 2 individual requests? Something akin to a join in SQL.
Your data model is very wrong, here is how to achieve what you want:
pk
sk
phone
email
other
user123
user123
0293480983
example#example.com
some map {}
SELECT * FROM mytable WHERE PK = 'user123'
This would allow you to get all of the information for a given userId. If you want the same information but this time by email, you create a GSI on the email attribute:
email
pk
sk
phone
other
example#example.com
user123
user123
0293480983
some map {}
SELECT * FROM mytable.myindex WHERE email = 'example#example.com'

DML trigger, creating new rows for several customers after insert/update/delete

I am using SQL Server 2017.
What I want to achieve: The database contains tables for customers, coupon codes and suppliers. A customer is a company. A customer may be an independent company, it may belong to another company, and it may have "child companies" (the connection between child and parent companies are established through a ParentID column in the customers table).
Coupon codes are related to customers. When a "parent company" activates access a coupon code, the code is supposed to become available for all the parent company's child companies. Likewise, if a parent company deactivates access to a coupon code, child companies should also lose access. As of today, this has to be fixed manually. I am writing a trigger that will take over this manual task.
A table CompanyCodes stores the relationship between companies and coupon codes. Column "Customer" stores the company ID number, column "Supplier" stores the ID of the supplier of the coupon code and column "Code" stores the coupon code.
Whenever a row is inserted, updated or deleted into/from the CompanyCodes table, the trigger first checks whether or not the relevant customer has any child companies. If it does, the trigger is supposed to insert/update/delete a row for each of the company's child companies, so that the changes are reflected in all of them.
E.g. customer 1 is the parent of customer 2 and customer 3. Customer 1 activates access to a new coupon code for supplier X, and a new row is inserted into CompanyCodes with the relevant information. In this case, the trigger is supposed to insert two new rows into the table, one for customer 2 and one for customer 3, where all the information (except the company ID) is the same as what was inserted for customer 1.
Where I am stuck: How do I make this work in cases where the customer has several child companies?
Here's the relevant part of my query as it currently stands (this is all within a IF statement that is executed when the trigger-firing action is "INSERTED")
DECLARE #insertedSupplier AS INT
DECLARE #insertedCode AS VARCHAR(50)
SET #insertedSupplier = (SELECT Supplier FROM inserted)
SET #insertedCode = (SELECT Code FROM inserted)
INSERT INTO dbo.CompanyCodes (Customer, Supplier, Code)
VALUES ((SELECT id FROM Customers WHERE Customers.ParentID = (SELECT Customer FROM inserted))
,#insertedSupplier, #insertedCode)
If there was a maximum of one possible child company, the above should work. But when there are several, "(SELECT id FROM Customers WHERE Customers.ParentID = (SELECT Customer FROM inserted)" will return several rows.
What would be simplest (and preferably best practice?) way of doing what I want to do here?
Edit with example showing desired output:
Customers table
| Customer | ID | ParentID |
|----------|----|----------|
|Customer1 | 1 | NULL |
|Customer2 | 2 | 1 |
|Customer3 | 3 | 1 |
Customer1 then proceeds to activate access to a new coupon code, and the CompanyCodes table changes to the following:
| Customer | Supplier | Code |
|----------|----------|----------|
|Customer1 | 123456 | abcdefgh |
The trigger then fires, and adds one row for each of Customer1's two child companies (where all the info, except for the Customer name, is the same as for Customer1):
| Customer | Supplier | Code |
|----------|----------|----------|
|Customer1 | 123456 | abcdefgh |
|Customer2 | 123456 | abcdefgh |
|Customer3 | 123456 | abcdefgh |
Edit 2: Also, the way our systems work, there is never more than one single insert/update/delete of a row in the CompanyCodes table (no batch jobs)

Database normalization. Which is better, inserting in one row or multiple row?

I'm currently designing my tables. i have three types of user which is, pyd, ppp and ppk. Which is better? inserting data in one row or in multiple row?
which is better?
or
or any suggestion? thanks
I would go for 3 tables:
user_type
typeID | typeDescription
Main_table
id_main_table | id_user | id_type
table_bhg_i
id_bhg_i | id_main_table | data1 | data2 | data3
Although I see you are inserting IDs for each user , I don't quite understand how are are you going to differentiate between the users , had I designed this DB , I would have gone for tables like
tableName: UserTypes
this table would contain two field first would be ID and second would be type of user
like
UsertypeID | UserType
the UsertypeID is a primary key and can be auto increment , while UserType would be your users pyd ,ppk or so on . Designing in this way would give you flexibility of adding data later on in the table without changing the schema of the table ,
the next you can edit a table for generating multiple users of a particular type, this table would refer the userID of the previous table , this will help you adding new user easily and would remove redundancy
tableName:Users
this table would again contain two fields, the first field would be the id call and the secind field would be the usertypeId try
UserId |UserName | UserTypeID
the next thing you can do is make a table to insert the data , let the table be called DataTable
tableName: DataTable
this table will contain the data of the users and this will reference then easily
DataTabID | DataFields(can be any in number) | UserID(refrences Users table)
these tables would be more than sufficient .If doubts as me in chatbox

SQL Server 2014 Set values to lookup table ID

If I have an address table and a cities lookup table and the address table has the cities in text instead of a foreign key, how would I replace the text with its counterpart in the lookup table?
Example:
Table luCities:
ID Name
--------------------
1 New Orleans
2 Portland
3 Seattle
Table Addresses:
ID Street City State Zip
--------------------------------------------------
1 123 main st. New Orleans OR 96556
should become
ID Street CityId State Zip
--------------------------------------------------
1 123 main st. 1 OR 96556
I have roughly 250 rows to match multiple cities with, so I'm hoping that a single UPDATE/SET statement can be used to match and modify them.
I believe you are looking for an update-join. If you add CityID to addresses as a FK to luCities, you can run this:
UPDATE Addresses SET
CityID = c.ID
FROM Addresses A
inner join luCities C on A.City = C.Name
Once everything looks correct, you can drop the old City column if you like.

MS Access - How do i use a table for a data type

Hi i am creating a contacts database and i want to use a create a cities table that i can use for the people table in the City field. How do i do this?
City table:
ID | City
--------------
1 | Wellington
2 | Auckland
3 | Christchurch
People Table Design
Field Name: City
Data Type: Short Text
Display Control: Combobox
Row Source Type: Table/Query
Row Source: City
These are my table design for the field City, but it is only showing the ID numbers in the combobox
I really am against the concept of Lookups in table. So I would suggest you to have a read of "The Evils of Lookup" before you proceed.
The problem is because you have used a table name as the RowSource. You need t modify some of the properties of the Field. In the lookup tab, change the Column Count to 2, Column Width to 0cm;2.04cm. Probably RowSource to
SELECT ID, City FROM City;

Resources