Codeigniter: how should I restructure db schema? - codeigniter

I don't even know if that's the right term.
May it be known that I'm a major novice!
I have three tables: users, profiles, and survey. Each one has user_id as it's first field, (auto-increment for users), and they're all tied by a foreign key constraint, CASCADE on DELETE.
Currently, for each user, let's say user_id 1, they have a corresponding db entry in the other tables. For profiles it lists all their information, and the survey table holds all their survey information.
Now I must change things...darn scope creep. Users need the ability to have multiple survey results. I imagine that this would be similar to a comment table for a blog...
My entire app runs around the idea that a single user is linked to a constraining profile and survey.
How should I structure my db?
How should I design my app's db so that a user can have multiple tests/profiles for the test?
Please assist! Any advice, information and personal-knowledge is appreciated!
Right now the only way I know how to accompany my client is to create a pseudo-user for each test (so unnecessary) and list them in a view table (called "your tests")-- these are obtained from the db by saying: where user_id=manager_id

Right now, survey has a foreign key to user, identifying the user who took the survey. This is good, and does not change.
But add an autoincrement primary key to survey (and to profile, too). Now a user can have multiple surveys. Each individual survey has its key, and its taker is identified by the user foreign key.
To find all surveys for all users:
select a.*, b,*
from user a
join survey b on (b.user_id = a.user_id);
To find all surveys for one user:
select a.*, b,*
from user a
join survey b on (b.user_id = a.user_id)
where a.user_id = some_user_id;
To just get the survey data, just select b.* only. For example:
select b.*
from survey b on
where a.user_id = ( select user_id from user a where a.name = 'Bob' );
Again, all you need to do is add a primary key (which should be an autoincrement) to survey.

Related

List of usernames in oracle

I need to get a list of all users and their tables and details.
For Example : https://www.google.com/search?q=oracle+user&source=lnms&tbm=isch&sa=X&ved=0ahUKEwi-td2pjcPMAhXEFh4KHdMAAVcQ_AUIBygB&biw=1175&bih=621#tbm=isch&q=oracle+user++sql+developer&imgrc=Qvmfp57HchgwgM%3A
In the above screen towards left there is red color symbol (User) , SO i need the username, associated tables(under that user) and atrributes in that table. Is this possible. for all users.
Thanks
Addy
ALL USERS, ALL TABLES, 'and details'
So do you really want ALL the users? Because many users are system users - users that own objects that the database itself uses, SYS being the biggest example. You could have dozens of these accounts. I'm guessing you don't want them.
All tables, tables in the recycle bin, tables there for materialized views, do you want those too?
And 'details'. Do you want their created date, their columns, their storage parameters? The more you want, the bigger and uglier your query is going to get.
All that being said, you pointed to a screenshot of Oracle SQL Developer. It contains a data modeling feature. Use it. Reverse engineer the users you really want into a data model. And then use the data dictionary reports it offers to give you the info you want.
You have to figure out what you REALLY want first though.
I talk about how to do the RE in the data modeler here.
You can start from this:
select *
from dba_tables t
inner join dba_tab_columns
using(owner, table_name)
This will give all the tables and columns, with some informations about tablespace, the type of the columns, and so on
This shows all the users and all their tables except for SYS and SYSTEM
SELECT owner, table_name
FROM All_All_Tables
WHERE owner NOT IN ('SYS','SYSTEM')
ORDER BY 1,2
Runs on Oracle 10, 11

Synonyms & materialized view

I have two tables. a) student b) restricted_student.
two users a) admin b) user
one synonyms stu for both the users. in admin it refer to student but for user it refer to restricted_student.
I want to create a materialized view MV .
The code of materialized view look like
CREATE MATERIALIZED VIEW SELECT TABLE_NAME,COLUMN_NAME FROM USER_TAB_COLUMNS;
such that if i am connected to admin then it should refer to student and for user it should refer to restricted_student by passing the only synonyms name stu.
something like
SELECT TABLE_NAME,COLUMN_NAME FROM USER_TAB_COLUMNS E='st';
the result i wanted when i connected to user it should give the restricted_student table columns. whereas whenever i connected to admin it should give the student table columns.
I created all the above objects.but materialized view is not giving the expected result as i want.
You can use a normal view where you can union these 2 tables and filter by the user logged in.
Also check Oracle RLS (row level security), https://docs.oracle.com/cd/B28359_01/network.111/b28529/intro.htm
Irrespective of the application and user, you can control how the where clause should be. That way you have a much higher control over the records that is queries.
For example,
Admin user
select * from stu;
Normal user
select * from stu;
Would have completely different results, based on the predicate you set for RLS.

Make a column a view

To be brief, I won't explain why I want to do this, just what I want to do.
I have two users (which I use as schemas) A and B. Both have a table USERS. Both USERS tables have a columns ID. Every A.USERS.ID is found in B.USERS.ID and every B.USERS.ID is found in A.USERS.ID (I put constraints on that). The only other shared columns between A.USERS and B.USERS is NAME and AGE.
EDIT: To make this clearer... The problem I have is that the values of NAME and AGE are not the same between schemas A and B. For example, user ID 723 in A has A.NAME='John Vincent'. In B, the B.NAME='JJ Vincent'. I want NAME and AGE to be the same at all times. So, I figure that I need to store it in one place and make it visible in two places.
When I let someone query B.USERS, I want B.USERS.NAME and B.USERS.AGE to actually be A.USERS.NAME and A.USERS.AGE. This is the query that I could use if I had permission to query both A and B:
select B.ID, A.NAME, A.AGE from B.USERS join A.USERS on B.USERS.ID=A.USERS.ID
However, I don't want to grant access to A to everyone. I only want to grant access to B (similarly, some people only have access to A and those people are the only ones I want to update the values of NAME and AGE).
I know I can't make just 2 columns be a view. Is there some other trick to make NAME and AGE be a view of A, but have permissions of B? I hope that I've explained enough to make sense. Just trying to avoid writing a dissertation.
You can grant update, insert, delete on B and A to whomever should be able to get to either or. If you want limited view based on your query, you can grant access solely to a view without granting access to the tables.
If you need column specific update access to B, then you can do "column level security" in oracle.
Something like "grant update (column_name) on table_name to user_name", and you'll have granted access to update only "column_name" in that table.

Relational Ado Without Primary Foreign Key Relation in yii

I have 2 tables. one is groups and other is frames.
groups has id, name, owner as columns.
grouppage has id,name and user_id.
users can have group pages. users can edit page if they are owner of the group .Means user_id = owner. Otherwise users can not edit the group page.
Hence i have a public property called can_edit.this is true if user_id = owner.
now i want to connect these 2 table using relational ADO. But how do i do it? because i have to connect the user_id in grouppage table to owner in groups. Neither owner nor group_id are primary keys?
Any solution /ideas
Thanks to all
Smith

SQL Server - How to auto-delete "old" database records?

I have a database table which storing shop list for users. I wish to store only 12 shop list per user, means if currently user1 has 12 records in the table, once user1 create a new shop list, the 1st shop list (oldest) will be deleted and the new shop list will be stored.
The ShopList table consist of ShopListID (PK), UserID (FK) and a LastUpdatedDate will is updated by a trigger once user insert/delete any shoplist item belong to the shoplist.
I got no idea how to do this at all.. is it using trigger? or stored procedure? really need help here...
Appreciate any feedback.. Thanks...
You can do this via a trigger or a procedure. You can also in your service layer/ business ligic layer query for the count there upon a save and remove the old records as well. Im for the business logic approach as it's more testable and keeps business logic out of triggers or procedures , so my recommendation is a code based approach.
I'd personally change the select query to only select the top 12 so that will control what the user can see.
I'd then use a database job that runs on a schedule that deletes the ones that you don't want.
I have come across this problem recently and it really depends on your "archiving" strategy.
What I have done is that I created a stored procedure that selects the records to be archived element onwards for every user account (my requirement is very similar to yours in the sense that i have to select the 31st element onwards in a user account). I can also give you some code here if you think it will come in handy.
I have created an extra table called XXXX_archive which is a clone of the schema on your shopping_list table(s). This is to insert old, archived records there in case a user asks to retrieve his list in the future (this is obviously optional but would come in handy).
The stored procedure finds this records and inserts them in the XXXX_archive table and then deletes them from the XXXX. This runs on a nightly basis (or whenever you feel its necessary) through the SQL Server Agent.
The effect is that the 13th element is not deleted the moment that the user creates another shopping list but i think thats fine cause you are in charge of your archiving strategy and can describe it in your TOS.
Just thought I should write my experience here cause i sorted out this problem just days ago.
EDIT: My stored proc is as follows:
INSERT into shopping_lists_archive
SELECT *
FROM shopping_lists
WHERE id in (
select id
from (
SELECT ROW_NUMBER() OVER (
PARTITION BY user_ID
ORDER BY user_ID desc) AS RowNumber,
id, user_ID
FROM shopping_lists c
where c.user_ID in (select USER_ID from shopping_lists group by user_id having COUNT(1) > 12)
) t
where rownumber > 12
)
DELETE FROM shopping_lists
WHERE id in (
select id
from (
SELECT ROW_NUMBER() OVER (
PARTITION BY user_ID
ORDER BY user_ID desc) AS RowNumber,
id, user_ID
FROM shopping_lists c
where c.user_ID in (select USER_ID from shopping_lists group by user_id having COUNT(1) > 12)
) t
where rownumber > 12
)
There you go - it may be slightly different than what you need cause i m archiving based on a join between two tables and had to amend my original query to your requirement.

Resources