How to model 'toggle' table in sql - sql

I have a table with some columns
CREATE TABLE test (
testid INT,
field1 CHAR(10),
field2 VARCHAR(50),
field3 DATETIME,
field4 MEDIUMINT
[...]
);
Now I want to be able to have a setting in my app that will allow me to to either enable or disable some of those for particular users.
CREATE TABLE user (
userid INT
);
I was thinking about:
CREATE TABLE user_test_visible (
userid INT,
field1 BOOL,
field2 BOOL,
field3 BOOL,
field4 BOOL
[...]
);
Also I was thinking about something like this :
CREATE TABLE user_test_visible (
userid INT,
field_name VARCHAR(30),
visible BOOL);
Are any of those approaches sensible?

I would suggest do something like this maybe.
CREATE TABLE test
(
fieldId INT,
field CHAR(10)
)
To have one table that contains the fields. Then if you need to add one more (change of requirements) you do not have to add a new column.
The I would skip the boolean and go with one table that has a shared primary key. Like this:
CREATE TABLE user_test_visible (
userid INT,
fieldId INT
);
The reason why I would suggest skipping the boolean is that if there is no row do show the field. That depends on what your start value is. If you want the users to see all field from the begining then you might consider having the table like this:
CREATE TABLE user_test_not_visible (
userid INT,
fieldId INT
);
Then where there is a row in this table then do not show the filed.
Edit
When use insert the field you must have some pre deployment script right? There you can also specify which columns that are visible and which is not. If you have different data types then ether have the layout like you have or you can just a sql_variant. But beaver that this type of column is not supported in for example linq-to-sql as a primary key.
That is just my idés. Hope it helps

Perhaps a more flexible approach would be to define "roles" within your application. A user would be associated with one or more roles, and each role would be associated with a set of columns. The union of those column sets would be what a user can see. This approach will require more effort to work out what columns a user can see, but it would make user management easier in the long term. It also separates user privileges from what that means in terms of database access.

Related

Postgresql SET DEFAULT value from another table SQL

I'm making a sql script so I have create tables, now I have a new table that have columns. One column has a FOREIGN KEY so I need this value to be SET DEFAULT at the value of the value of the original table. For example consider this two table
PERSON(Name,Surename,ID,Age);
EMPLOYER(Name,Surname,Sector,Age);
In Employer I need AGE to be setted on default on the AGE of Person, this only if PERSON have rows or just 1 row.
ID is Primary key for person and Surname,Sector for employer and AGE is FOREIGN KEY in Employer refferenced from Person
Example sql :
CREATE TABLE PERSON(
name VARCHAR(30) ,
surename VARCHAR(20),
ID VARCHAR(50) PRIMARY KEY,
Age INT NOT NULL,
);
CREATE TABLE EMPLOYER(
name VARCHAR(30) ,
Surename VARCHAR(20),
Sector VARCHAR(20),
Age INT NOT NULL,
PRIMARY KEY (Surename,Sector),
FOREIGN KEY (Age) REFERENCES Person(Age) //HERE SET DEFAULT Person(Age), how'??
);
Taking away the poor design choices of this exercise it is possible to assign the value of a column to that of another one using a trigger.
Rough working example below:
create table a (
cola int,
colb int) ;
create table b (
colc int,
cold int);
Create or replace function fn()
returns trigger
as $$ begin
if new.cold is null then
new.cold = (select colb from a where cola = new.colc);
end if;
return new;
end;
$$ language plpgsql;
CREATE TRIGGER
fn
BEFORE INSERT ON
b
FOR EACH ROW EXECUTE PROCEDURE
fn();
Use a trigger rather than a default. I have done things like this (useful occasionally for aggregated full text vectors among other things).
You cannot use a default here because you have no access to the current row data. Therefore there is nothing to look up if it is depending on your values currently being saved.
Instead you want to create a BEFORE trigger which sets the value if it is not set, and looks up data. Note that this has a different limitation because DEFAULT looks at the query (was a value specified) while a trigger looks at the value (i.e. what does your current row look like). Consequently a default can be avoided by explicitly passing in a NULL. But a trigger will populate that anyway.

CREATE TABLE where multiple columns are inserted with same value

Lets say I have a CREATE TABLE code like this:
CREATE TABLE Test (
ID int NOT NULL IDENTITY(1,1),
SortIndex int,
Name nvarchar(50) NOT NULL
);
I was wondering if it's possible to make a table in MSSQL which had the ability to insert the ID's value into the SortIndex column when I run an INSERT.
So I would run this INSERT:
INSERT INTO Test (Name) VALUES ('Awesome Dude');
Which would normally yield the row:
ID,SortIndex,Name
1,NULL,"Awesome Dude"
But I'd like it to automatically be:
ID,SortIndex,Name
1,1,"Awesome Dude"
Is this even possible by altering the CREATE TABLE script, or do I have to use a TRIGGER?
I would be inclided to take a slightly different approach to this. If you want your SortIndex to default to the ID, but be overridable, I would use a nullable column, and a computed column:
CREATE TABLE Test (
ID int NOT NULL IDENTITY(1,1),
OverrideSortIndex int,
Name nvarchar(50) NOT NULL,
SortIndex AS ISNULL(OverrideSortIndex, ID)
);
If you need to change the sort index for any reason, update the column OverrideSortIndex and this takes precedence.

Creating a table specifically for tracking change information to remove duplicated columns from tables

When creating tables, I have generally created them with a couple extra columns that track change times and the corresponding user:
CREATE TABLE dbo.Object
(
ObjectId int NOT NULL IDENTITY (1, 1),
ObjectName varchar(50) NULL ,
CreateTime datetime NOT NULL,
CreateUserId int NOT NULL,
ModifyTime datetime NULL ,
ModifyUserId int NULL
) ON [PRIMARY]
GO
I have a new project now where if I continued with this structure I would have 6 additional columns on each table with this type of change tracking. A time column, user id column and a geography column. I'm now thinking that adding 6 columns to every table I want to do this on doesn't make sense. What I'm wondering is if the following structure would make more sense:
CREATE TABLE dbo.Object
(
ObjectId int NOT NULL IDENTITY (1, 1),
ObjectName varchar(50) NULL ,
CreateChangeId int NOT NULL,
ModifyChangeId int NULL
) ON [PRIMARY]
GO
-- foreign key relationships on CreateChangeId & ModifyChangeId
CREATE TABLE dbo.Change
(
ChangeId int NOT NULL IDENTITY (1, 1),
ChangeTime datetime NOT NULL,
ChangeUserId int NOT NULL,
ChangeCoordinates geography NULL
) ON [PRIMARY]
GO
Can anyone offer some insight into this minor database design problem, such as common practices and functional designs?
Where i work, we use the same construct as yours - every table has the following fields:
CreatedBy (int, not null, FK users table - user id)
CreationDate (datetime, not null)
ChangedBy (int, null, FK users table - user id)
ChangeDate (datetime, null)
Pro: easy to track and maintain; only one I/O operation (i'll come to that later)
Con: i can't think of any at the moment (well ok, sometimes we don't use the change fields ;-)
IMO the approach with the extra table has the problem, that you will have to reference somehow also the belonging table for every record (unless you only need the one direction Object to Tracking table). The approach also leads to more I/O database operations - for every insert or modify you will need to:
add entry to Table Object
add entry to Tracking Table and get the new Id
update Object Table entry with the Tracking Table Id
It would certainly make the application code that communicates with the DB a bit more complicated and error-prone.

SQL Server 2008 stored procedure for a table having two foreign keys and both of them is a composite key

I have the following tables :
create table ApartmentInfo(
ApartmentId int primary key identity,
ApName nvarchar(50))
create table [User](
UserId int primary key identity,
FirstName nvarchar(50),
LastName nvarchar(50),
Username nvarchar(50),
[Password] nvarchar(50),
[Description] nvarchar(200))
create table ApUser(
ApartmentId int foreign key references ApartmentInfo(ApartmentId),
UserId int foreign key references [User](UserId),
primary key(ApartmentId,UserId))
Summary of the usage is: suppose I have 10 apartments in my Apartmentinfo table and 3 users in the [User] table.
Now I want to write a stored procedure such that:
every UserId has all 10 ApartmentId's, and whenever a new apartment is created in ApartmentInfo table it will also be added in ApUser table again having all 3 userId's.
And if a new user is created in User table then it will also have all the 10 ApartmentId's related with it in ApUser table.
Thanks in advance, I am new to SQL Server and I don't know how it can be done or not but, if it is possible then please let me know, I will be grateful to you, thanks.
If you're not dead set on using a stored procedure this use case seems like an excellent fit for server side triggers:
IF EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[trigger_insert_apartment]'))
DROP TRIGGER [dbo].[trigger_insert_apartment]
GO
CREATE TRIGGER trigger_insert_apartment
ON ApartmentInfo FOR INSERT
AS INSERT ApUser(ApartmentId, UserId ) SELECT i.ApartmentId, u.UserId FROM [User] AS u, inserted AS i
GO
IF EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[trigger_insert_user]'))
DROP TRIGGER [dbo].[trigger_insert_user]
GO
CREATE TRIGGER trigger_insert_user
ON [User] FOR INSERT
AS INSERT ApUser(ApartmentId,UserId ) SELECT a.ApartmentId, i.UserId FROM ApartmentInfo AS a, inserted AS i
GO
These two triggers will insert all apartments or users into the apinfo table when you add a new user or apartment, and if I understood your question that was what you wanted?
To address your question about what you'd do to associate apartments with users IF YOU WANTED TO LATER...
If you're restricting which apartments a user has access to view, I would NOT associate them individually to every user. BUT, if they're manually adding a "watch" on an apartment in your application, then this is ok to do. If you want to only show them a certain set of apartments, try to group them in a logical way if you can. So maybe have an ApartmentGroup lookup table:
ApartmentGroup(ApartmentGroupId (Int), ApartmentGroupName varchar(50))
and assign an ApartmentGroupId to each apartment. Then you can have a join table for ApUser and ApartmentGroup. That way you're not associating every apartment with every user.
However, if you want to add the apartment to each user still, then in your InsertApartment stored procedure, just insert it into the ApUser table as well.

Create a unique float id?

I don't know how to phrase this question, but I'm trying to do this:
alter table [TEMP]
add SEQID int identity(1,1)
This works; however, what I really need is a float column instead of an int:
alter table [TEMP]
add SEQID **FLOAT** identity(1,1)
I think this is illegal. Please let me know if it is not.
Is there a work around to getting a float ID column?
Edit: Is there a way to create the identity column as int, then remove the identity attribute, and then convert the column to a float?
You can do what you want as:
create table temp (
id int identity(1,1),
fid as cast(id as float)
)
This adds the id as an integer but then has another column that is computed by converting it to float.
Why are you creating new ids for a legacy system?
Or, you can add the computed column to an existing table:
alter table temp add fid as cast(id as float)
I don't know if I understand why you want a floating point ID. That column is usually just stored as an int (bigint, smallint, depends on the table...) but an int will uniquely identify each row of the table sufficiently to allow you to query each of them without data contamination. You just have to make sure to Join the tables correctly.
If you're really sure about using float, then I think this would suffice, unless I'm missing something:
alter table [TEMP]
add SEQID float identity(1,1)