I have a requirement which is to keep the data of 2000 employees attendance.
So the attendance table should have design?
365 columns of each day in a year, 2000 pre-inserted records
And i will update it daily via java program
or
5 columns 2000 records daily insert for 365 days?
Or is there any better approach?
I think you're over-thinking things. Assuming you already have an employee table with the employees' details, all you really need is a another table with the employee's ID and the date (and possibly entrance and exit times, if you care about it), where the presence of a row indicates attendance on that date and the lack of if indicates lack of attendance. You can then find this absence days by left joining on the employee table.
CREATE TABLE employee (
id NUMBER PRIMARY KEY,
-- other details...
);
CREATE TABLE attendance (
employee_id NOT NULL REFERENCES employee(id),
attendance_date DATE NOT NULL,
PRIMARY_KEY(employee_id, attendance_date)
);
Related
Oracle newbie here. I need to build a database which fulfils the requirements below:
A department is allowed to register for only two programs in a year
The maximum participants in each program must not exceed the number of people in respective departments.
*There are 14 departments in total.
As per requirement, seems like I have to restrict the number of rows inserted.
For example, if the total number of people in Department A is 100, the 101st row has to be rejected.
Apologies if there are many errors as I'm writing this question because now is 1.30AM. I tried to keep the table simple with less columns so it's easier to test the code.
CREATE TABLE department(
DEPT_ID CHAR(5) not null primary key,
TOTAL_P NUMBER);
CREATE TABLE participant(
P_ID CHAR(5) not null primary key,
DEPT_ID CHAR(5) not null);
CREATE TABLE program(
PROG_ID CHAR(5) not null primary key,
PROG_NAME VARCHAR(30),
DEPT_ID CHAR(5),
START_DATE DATE,
END_DATE DATE,
FOREIGN KEY(DEPT_ID) references department(DEPT_ID) on delete cascade);
and I have tried using trigger, but I keep getting warning: trigger created with compilation errors.
(I tried to count the rows in table program and group them by dept_id, then proceed to check the condition)
CREATE OR REPLACE TRIGGER prog
BEFORE INSERT ON program
DECLARE
CountRows NUMBER;
BEGIN
SELECT COUNT(*)
INTO CountRows
GROUP BY DEPT_ID
FROM program;
IF CountRows > 2 THEN
RAISE_APPLICATION_ERROR(-20001, 'Only 2 programs are allowed');
END IF;
END;
/
I don't even know if my idea does make sense or not. I tried many other ways like putting the condition where(to specify dept_id) before begin, after begin, I still get the warning. I have been experimenting a whole day and still cannot figure it out.
MY QUESTIONS:
Is it better to create multiple conditions in one trigger as I will have 14 departments?
if so, how to do that without getting the warning?
any alternative way to restrict the number of rows?
Any help, hints, tips, anything, is deeply appreciated. thanks.
You could do it by maintaining in the trigger handling insert/update/delete operation on the "child" table (e.g. the program), an intersection table "parent_child" (e.g. department_program) containing the 2 foreign keys on the parent/child tables, and an index on which you will put the check constraint (e.g. < 3 for the number of program per department) + any other column defining the scope of the constraint (e.g. here the year of the start_date of the program). The 2 columns with the FK, the index and the other scope columns should be the PK of this intersection table.
e.g.
CREATE TABLE program_department
(
DEPT_ID CHAR(5),
PROG_ID CHAR(5),
PROG_YEAR NUMBER(4),
PROG_IDX NUMBER(10,0) DEFAULT 0,
-- to force always equal to a number the constraint must be defererrable
CONSTRAINT CK_PROG_IDX CHECK (PROG_IDX >= 0 AND PROG_IDX < 3) ENABLE,
PRIMARY KEY (PROG_ID, DEPT_ID, PROG_YEAR, PROG_CNT)
)
;
The idea is to maintain the PROG_IDX that will contain the index of the relation between the department and the program of the specific year.
In the trigger on the table program, you have to update the program_department according to each action, when updating/removing this may imply/implies decrementing the PROG_IDX of the ones having PROG_IDX greater than the one removed.
And of course you will have to apply about the "same" logic for the participant's relationship, however there you can't hardcode the constrain by a CHECK since the # of people in each department is not known at compile time. This case is more complex also because you have to think about the consequence of changes of the # of persons in a department. Probably you will have to keep in the intersection table, the # of people in the department at the start_date of the program.
Say I have a column in Postgresql DB like this to represent booking system for desk in an office. In a day, a person can only book a desk.
ID
Booked_Date
Seat_ID
Employee_ID
1
2022-07-08
10C
id1
2
2022-07-08
20C
id2
When booking a desk, the system need to check whether that person has booked any other desk or other person has booked that desk before inserting the booking data. So, something like this for example:
select count(*) as today_book from booking where (booked_date=today and seat_id='10C')
or (booked_date=today and employee_id='id1')
if(today_book == 0) {
insert into booking values(today, book_seat, current_employee_id)
}
To avoid duplicate data (a desk booked by more than one person), how can I do it in Postgresql? I am using Postgresql 11.xx version.
I am thinking about using Plpgsql or stored procedure and wrapped around above logic in it.
You need two unique constraints:
ALTER TABLE booking ADD CONSTRAINT seat_unique_per_day
UNIQUE (booked_date, seat_id);
ALTER TABLE booking ADD CONSTRAINT employee_unique_per_day
UNIQUE (booked_date, employee_id);
Then you simply try to INSERT and catch and handle constraint violation errors in your application.
I am using PostgreSQL and am trying to restrict the number of concurrent loans that a student can have. To do this, I have created a CTE that selects all unreturned loans grouped by StudentID, and counts the number of unreturned loans for each StudentID. Then, I am attempting to create a check constraint that uses that CTE to restrict the number of concurrent loans that a student can have to 7 at most.
The below code does not work because it is syntactically invalid, but hopefully it can communicate what I am trying to achieve. Does anyone know how I could implement my desired restriction on loans?
CREATE TABLE loan (
id SERIAL PRIMARY KEY,
copy_id INTEGER REFERENCES media_copies (copy_id),
account_id INT REFERENCES account (id),
loan_date DATE NOT NULL,
expiry_date DATE NOT NULL,
return_date DATE,
WITH currentStudentLoans (student_id, current_loans) AS
(
SELECT account_id, COUNT(*)
FROM loan
WHERE account_id IN (SELECT id FROM student)
AND return_date IS NULL
GROUP BY account_id
)
CONSTRAINT max_student_concurrent_loans CHECK(
(SELECT current_loans FROM currentStudentLoans) BETWEEN 0 AND 7
)
);
For additional (and optional) context, I include an ER diagram of my database schema.
You cannot do this using an in-line CTE like this. You have several choices.
The first is a UDF and check constraint. Essentially, the logic in the CTE is put in a UDF and then a check constraint validates the data.
The second is a trigger to do the check on this table. However, that is tricky because the counts are on the same table.
The third is storing the total number in another table -- probably accounts -- and keeping it up-to-date for inserts, updates, and deletes on this table. Keeping that value up-to-date requires triggers on loans. You can then put the check constraint on accounts.
I'm not sure which solution fits best in your overall schema. The first is closest to what you are doing now. The third "publishes" the count, so it is a bit clearer what is going on.
so I had this one SQL problem asked to me on a coding challenge and I initially understood it wrong. Basically given an Employee table, with a primary key being EmployeeID theres also a column named say ManagerID. That ManagerID references a primary key in the same Employee table. Let's say EmployeeID 1's Manager is EmployeeID 3 who has a manager with EmployeeID 4.
How would a query look like to list all the Employees next to their managers? I'm a novice when it comes to SQL but is there a way to do this with say a for/while loop since it's possible for a low level employee to link all the way up the chain of command many times?
I am a bit lost as to how to explain this, so I will try to give an example of some tables (+ data) and then the result that I am after (all my table columns are NOT NULL):
Table: Customers
Id int primary key
Name varchar(250)
Table: Stats (Date, CustomerId is the primary key)
Date (date)
CustomerId (int) - foreign key to Customers table
Earning (money)
Table: Bonus
Id int primary key
CustomerId int - foreign key to Customers table
Date date
Amount money
Table: Payments
Id int primary key
DateFrom date,
DateTo date,
CustomerId bigint - foreign key to Customers table
Table: CampaignPayment
Id int primary key
PaymentId int - foreign key to payments table
Quantity int
UnitPrice money
Table: BonusPayment
Id int primary key
PaymentId int - foreign key to payments table
Amount money
The idea here is that everytime a customer does something that is supposed to earn them money, it goes into the stats table. Customers can also receive different kinds of bonuses which goes into the bonus table. Every so often I need to create an invoice for the customers (Payments table) which will list the stuff from the stats table + the bonus table within the specified time period and that will generate the invoice (that is the payments table defines who the invoice is for, which period and the campaignpayment and bonuspayment table defines what is being paid and why).
Now - I need to be able to join all these tables up to be able to get an output of the following:
CustomerId | CustomerName | PaymentId | Amount | BonusAmount | DateFrom | DateTo
Amount is the summed Amount ( SUM(Quantity * UnitPrice) ) from the CampaignPayment table, and BonusAmount is the summed Amount ( SUM(Amount) ) from the BonusPayment table. DateFrom and DateTo is from the Payments table.
The trick is that for every customer within a given month where every single day of that month is not covered, I want a row with the following data:
CustomerId | CustomerName | NULL | (Stats.Earning - Amount Earned from possible payments within the month) | (Bonus.Amount - Amount Earned possible bonuses that is in payments within the month) | First day of month | Last day of month
I may need a bit more of complex logic as to how to calculate the amount and bonus amount within these "empty" rows but as for now, that is what I need to begin with.
How would I go about this? I know how to get the "initial" bit done, but how would I go about adding in these "empty" rows? I hope I explained the problem well enough in detail and that you can see the idea here - if not let me know and I will try to explain further.
The database is MS SQL Server 2008.
EDIT: Also alternatively an "empty" row for every customer per month is also and acceptable solution.
I'd make an auxiliary table with "every single day of that month" to ease identifying if "every single day of the month is not covered" (a somewhat ambiguous spec, but the aux table should help whether you mean "no day is covered" or "some days are not covered" and whether a day is considered "covered" if it has either a bonus or stats, or if it needs to have both to be considered "covered" -- these ambiguities are why I'm not going to even try and sketch the SQL using this aux table;-). Then I'd UNION the "empty rows" to the "initial bit" that you already know how to get done -- seems a perfect task for UNION!-)