SQL Server - How to auto-delete "old" database records? - asp.net-mvc-3

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.

Related

Hi there, I'm using Oracle. I want to create a view where in this view, I display the rows of the same primary key and the total number of coin sales

There's a couple of tables that I need to use columns from in the select statement. the questions is: Create a View to display the employee id, first name and surname. In your query include the coin price and a 10% commission for the sales made by the employees.
the difficult part for me is that employees of the same employee number, can make multiple coin sales, so in the view, i need to be able to add all the coin sales together of each respective primary key (employee_id)
As you can see in this image, emp101 has sold two different coins, with the coin_id's of "7116" and "7112". In the view i want to be able to somehow tally each coin value that each employee_id has sold if that makes sense ?
There's multiple other tables, but there's too many to send, so i am just trying to get a general idea of how to do this. I understand the logistics of the question, i just dont know how to implement the answer with the correct syntax and methods etc...
Since this appears to be a homework question, here is a discussion of how to solve it:
You want to CREATE a VIEW and give the view a name (something like employee_commisions) and include 5 columns (employee_id, first_name, surname, coin_price and commission - or maybe only 4 columns if they want the combined price plus commission).
To get the values for that view, you want to SELECT ... FROM existing tables; however, your image does not include first_name, surname or a value for a coin so I am assuming that you will have an employees table and a coins table that you will need to INNER JOIN to the invoice table on their respective primary keys.
To get the total value for the coins, you want to aggregate the values and this would be done with the SUM aggregation function and, so that you get the value for each employee, you would need to GROUP BY the employee_id primary key. You will either need to include the other columns you are not aggregating by in the GROUP BY clause or apply an aggregation function to those columns such as MAX(surname).
The syntax for CREATE VIEW is here.
The syntax for SELECT is here.

hive: how to handle scd type 2 without update

currently in our on-prem Hadoop environment we are using hive table with transaction properties. However as we have moving to AWS we don't have that feature yet. and so want to understand how to handle SCD Type 2 without updates.
for example.
for following record.
With Updates
In table with transaction properties enabled, when I get an update for a record, I go ahead and change the end_date to current date and create new record with effective_date as current date and end_date as 12/31/9999, as shows in above table. And so it's easier to find my active record (where end_date = "12/31/9999").
However, if I can't update the past record. I have two records with same end_date. as shows in table below.
My question are.
if I can update end_date of past record,
How do I get the historical duration of stay?
How do i get active record?
without updates
First of all, convert all dates to the 'yyyy-MM-dd' format, so they all will be sortable and analytic functions will work. Then you can use lead(effective_date, '2019-01-01') over(partition by id order by effective_date). For id=1 and effective_date = 2019-01-01 it should give you '2020-08-15' and you can assign this value as end_date for '2019-01-01' record. If there is no record with bigger effective_date, '9999-01-01' will be assigned. After this transformation Active record is that having '9999-01-01'.
Suppose dates are already converted to yyyy-MM-dd, this is how you can rewrite your table (after insert):
insert overwrite table your_table
select name, id, location, effective_date,
lead(effective_date,'2019-01-01') over(partition by id order by effective_date) as end_date
from your_table
Or without doing insert first, you can UNION ALL existing records with new records, in a subquery, then calculate lead.
Actually, SCD2 is not recommended for historical data rewriting because of non-equi join implementation in hive. It is implemented as cross-join + filter (or duplicating join on dim.id=fact.id (this will duplicate rows) + where fact.date<=dim.end_date and fact.date>=dim.effective_date - this should filter one record). This join is very expensive if the dimension and fact are big because of duplication before filtering.

How to limit a table to 5 records with a certain field combination

I'm using MS Access 2016.
Suppose I have a Student table, a Subject table (ie Geography, History etc) and a StudentSubject table that records which subjects each student has chosen.
StudentSubject contains StudentId and SubjectId as foreign keys.
No student is to choose more that 5 subjects.
Is there any way to define a validation rule on the table such that a given StudentId may not appear in the StudentSubject table more than 5 times?
I could enforce the contraint by introducing an additional table, but if possible, I like to avoid that.
I also want to define a constraint at table level, rather than use vba code that gets invoked when a record is inserted via a form. Access, as far as I know, has no such thing as triggers, as one would have in an sql system.
You can use a CHECK constraint to limit the possibilities:
ALTER TABLE StudentSubject
ADD CONSTRAINT Max5Subjects
CHECK(
NOT EXISTS(
SELECT 1
FROM StudentSubject
GROUP BY StudentID
HAVING Count(StudentID) > 5
)
)
Note that this might slow down data entry a bit, especially if StudentID is not indexed.
Check constraints need to be executed either in ANSI 92 compatible mode, or using ADO (e.g. using CurrentProject.Connection.Execute). More details here
To execute it using ADO, you can just use this single line in the immediate window:
CurrentProject.Connection.Execute "ALTER TABLE StudentSubject ADD CONSTRAINT Max5Subjects CHECK(NOT EXISTS( SELECT 1 FROM StudentSubject GROUP BY StudentID HAVING Count(StudentID) > 5))"
Also, keep in mind that if somehow there are records that violate the constraint (e.g. because they were present before the constraint got added), your table will get locked down fully.

How to optimize this select query

Hi I'm using the below select query which fetches all the rows from the table based on a single condition. It is like an export that we are geenrating. Here is the query.
Select emp_name, phone_number, emp_id from Employees where
emp_dept = 100;
Suppose if i have millions of records here and i'm not allowed to create any temporary table and index, what is the best way to optimize this query. Please note i need all the records of the table so the filters are actually less.
In the process of learning Oracle. So please let me know in case any mistakes are there.
Thanks.
Since
i'm not allowed to create any temporary table and index
then your only option seems to be to run this in parallel:
select --+ parallel(E,16)
emp_name, phone_number, emp_id
from employees E
where emp_dept = 100;
And your useful options are, depending on many factors ...
to ask your local DBA to add an index for you
to ask your local DBA to reorganize the table for you (partitioning, clusters)
to ask your local DBA to create a on-commit fast-refreshable query-rewritable mview for you
to ask your company to buy Exadata machine for you
etc.

Codeigniter: how should I restructure db schema?

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.

Resources