Relation between users with messages - sql

I have a table of Users:
create table dbo.User
(
Id int identity not null,
Name nvarchar (400) null,
// Other coluns as Login, Password, etc.
)
create table dbo.Role
(
Id int identity not null,
Name nvarchar (20) null
)
create table dbo.UserRole
(
UserId int not null,
RoleId int not null
)
Each user has one or more roles.
I need to relate users one to each other in periods of type.
For example, one professor to its students during 4 months in 2015.
And I also need to track messages between users.
One of my ideas would be the following:
create table dbo.UserToUser
(
FirstUserId int not null,
SecondUserId int not null,
StartDate datetime not null,
EndDate datetime not null
)
Being both FirstUserId and SecondUserId FK's of Users table.
create table dbo.Message
(
ToId int not null,
FromId int not null,
Text nvarchar(max) not null,
Created datetime not null
)
Being both ToId and FromId FK's of Users table.
Should this be done in another way?

This seems fine but you could be more generic with the relationships. For example you might want to have more than 2 people in a relationship. There are a number of ways to do this but I would do it like this:
Relationship
------------
ID
StartDate
EndDate
Category
... etc
RelationshipMembers
-------------------
RelationshipID
UserID
Order (may not be needed)
MembershipCategory (eg Professors and Students // messageFrom and messageTo)

Related

Self-Referencing Table SQL Select last element from included elements

I have tables:
create table Branches(
Id int primary key identity,
IdSection int not null,
IdMasterBranch int null,
[Name] varchar(100) not null,
[Description] varchar(300) null
)
create table Threads(
Id int primary key identity,
IdBranch int not null,
IdUserAuthor int not null,
[Name] varchar(100) not null,
IsPinned bit not null,
IsOpen bit not null,
HasPoll bit not null
)
create table Posts(
Id int primary key identity,
IdThread int not null,
IdUserAuthor int not null,
Body varchar(4000) not null,
IsEdited bit not null,
[Index] int not null,
Created datetime2 not null,
Updated datetime2 null
)
Branches is self referencing table, that contains another branches.
And i wanna write sql request to select all master branches (IdMasterBranch IS NULL) with last thread and last post.
Something like this:
select * from Branches branch
left join BranchModerators moderator on branch.Id = moderator.IdBranch
left join Threads thread on branch.Id = thread.IdBranch
left join (select * from (
select *,
ROW_NUMBER() over (
partition by IdThread
order by [Index] desc
) as RowNumber
from Posts
) groups
where groups.RowNumber = 1) lastPost on thread.Id = lastPost.IdThread
But i wanna take last thread and post with included inner branches too.
What is the best solution for it?

Insert into multiple(7) tables with no duplicates

Trying to create a query/SP that will take data from one table and insert it into multiple tables. I have one main table that everything is put into at the beginning like a temp table.
Temp table
CREATE TABLE Employee
(
userID INT IDENTITY(1,1) NOT NULL,
userName VARCHAR(50) NULL,
FirstName VARCHAR(50) NULL,
LastName VARCHAR(50) NUll,
UserPassWd VARCHAR(50) NULL,
EmailId VARCHAR(100) NULL
CONSTRAINT PK_Employee PRIMARY KEY (userID)
)
Than when employee is verified it will be split up into multiple tables that only need a field or two from the temp table as needed. The UserEmail table I have listed below is one of the tables. I'm trying to get it to work for one table right now and then I'm guessing i will just copy the insert part and change the table name and attributes to the new tables
Here is what i have so far.
DECLARE #EMAIL VARCHAR(100)
DECLARE #USERID INT
SELECT #USERID = userID
,#EMAIL = EmailId
FROM Employee
WHERE userID = 1004
INSERT INTO UserEmail
(
EmailAddress
,EmailTypeID
,ExternalUserID
,Active
,CreatedByID
,CreatedDate
,UpdatedByID
,UpdatedDate
)
SELECT #EMAIL -- Email Address
,1 -- Email Type
,1 -- ExternalUserID
,1 -- Active
,1 -- CreatedByID
,CURRENT_TIMESTAMP -- CreatedDate
,1
,CURRENT_TIMESTAMP -- UpdatedDate
FROM Employee X
WHERE 1=1
AND X.userID = '####'-- INSERT USERID HERE for testing
This will insert the record into the UserEmail table but will create duplicate users, which i cant have so I tried adding this but it doesn't do what I want it to do.
WHERE 1=1
AND NOT EXISTS(
SELECT userID
FROM Employee
WHERE userID = 1004
)
Any guidance or help would be much appreciated. Thank You!
If you only like NOT to insert to UserEmail if user already exists just extend
INSERT INTO UserEmail ....
SELECT ....
FROM ....
WHERE ..
AND NOT EXISTS (select 1 from UserEmail where EmailAddress = X.emailAddress)
Otherwise review MERGE syntax (https://learn.microsoft.com/en-us/sql/t-sql/statements/merge-transact-sql)

Get AutoIncrement ID and insert into Foreign Key Table

I have 3 tables User, Profile and ProfilePicture. Profile and ProfilePicture have a foreign key relation with User table. What I want to do here is whenever I insert data into the User table through web application their AutoGeneratedID get and inserted into Profile and ProfilePicture tables.
CREATE TABLE User
(
UserId INT(11) NOT NULL AUTO_INCREMENT,
Username VARCHAR(45) NOT NULL,
Password VARCHAR(50) NOT NULL,
PRIMARY KEY (`UserId`),
UNIQUE INDEX `UserIdId_UNIQUE` (`UserId` ASC)
);
CREATE TABLE Profile
(
UserId INT(11) NOT NULL,
Firstname VARCHAR(50) NULL,
Lastname VARCHAR(50) NULL,
FOREIGN KEY (UserId) REFERENCES User (UserId)
)
CREATE TABLE ProfilePicture
(
UserId INT(11) NOT NULL,
Picture image NULL,
insertdate date NULL,
FOREIGN KEY (UserId) REFERENCES User (UserId)
)
I know I have to use a trigger but I don't understand how to do this.
I am supposing that you are doing this using stored procedure or raw queries. This thing can be achieved by using OUTPUT clause.
Define a local table with column Id
DECLARE #OutputTbl TABLE (ID INT)
Now when you save the User then insert the new gnerated id into #OutputTbl
INSERT INTO User (Username, Password)
OUTPUT INSERTED.UserId INTO #OutputTbl(ID)
VALUES ('name', 'password')
Now when you need this id in Profile/ProfilePicture, get this id from local table
insert into Profile (
UserId ,
Firstname,
Lastname) Values ((Select ID from #OutputTbl),'fName','lName')
You can try something as below :
CREATE TABLE #tempUser(
UserId INT,
ShopRef INT
)
INSERT INTO [User] (UserPassword,Name,MobileNo,Gender,Dob,Country,State,City,StreetAddress
,ZipCode,IsActive
,CreatedDate,ModifiedBy,CreatedBy,IsAdmin,EmailOtp,UserImage,Rating
,ContactNo)
OUTPUT inserted.UserId, inserted.EmailOtp INTO #tempUser
SELECT 'NA', [Name], [MobileNo], '-','1900-01-01',[Country],[State],[City],[StreetAddress],
[ZipCode], 1
,#Date,#UserId,#UserId,0,ID,'NA',0
,'NA'
FROM #temp WHERE Status ='SUCCESS'
If you are executing these inserts in the same SP then you can use, make sure UserId is an Identity Column :
SET #UserId = SCOPE_IDENTITY()
you can after insert into table, call SCOPE_IDENTITY() function, to get the latest
identity inserted
for more informatin see:
https://msdn.microsoft.com/en-us/library/ms190315.aspx
http://www.codeproject.com/Articles/103610/Difference-between-IDENTITY-SCOPE-IDENTITY-IDENT-C

Tables with multiple relationships

I have two tables AdmissionExams and PeriodicalExams:
create table dbo.AdmissionExams
(
Id int identity not null
AnalysisId int null, FK to Analyses Table
ClassificationId int not null, FK to Classifications Table
ProfessorId int not null, FK to Professors Table
StudentId int not null, FK to Students Table
-- Other admission exam columns
)
create table dbo.PeriodicalExams
(
Id int identity not null
AnalysisId int null, FK to Analyses Table
ClassificationId int not null, FK to Classifications Table
ProfessorId int not null, FK to Professors Table
StudentId int not null, FK to Students Table
-- Other periodical exam columns
)
One exam has no Analisys or one Analisys. And one Analisys has only one Exam.
One exam has always one and only one Classification. And one Classification has only one Exam.
One exam has one and only one Student and only one Professor.
But one student and one professor can have multiple exams.
Is my business model ok? I am not sure about the FKs.
The Analysis and Classification table are the same for both type of exams.
I suggest you that use inherited table in Table per type format.
create table dbo.Exams
(
Id int identity not null
AnalysisId int null, FK to Analyses Table
ClassificationId int not null, FK to Classifications Table
ProfessorId int not null, FK to Professors Table
StudentId int not null, FK to Students Table
)
create table dbo.AdmissionExams
(
Id int not null
-- Other admission exam columns
)
create table dbo.PeriodicalExams
(
Id int not null
-- Other periodical exam columns
)
ALTER TABLE dbo.AdmissionExams ADD CONSTRAINT [FK_AdmissionExams_Exam] FOREIGN KEY(Id) REFERENCES dbo.exam (Id)
ALTER TABLE dbo.PeriodicalExams ADD CONSTRAINT [FK_PeriodicalExams_Exam] FOREIGN KEY(Id) REFERENCES dbo.exam (Id)
Rather You should have one exam table and a column to define its type. Depending on the amount of information you have to capture for Classification and Analysis it might be be better to add them directly to the exam tables also (Given the 1 to 1 relationship).
create table dbo.Exams
(
Id int identity not null
ExamType varchar(20) null,
AnalysisInfo varchar(20) null,
ClassificationInfo varchar(20) null,
ProfessorId int not null, FK to Professors Table
StudentId int not null, FK to Students Table
)

SQL Logic and Aggregate Issue

I have the following problem to solve in SQL :
d) A query that provides management information on take up of the various types of activities on offer. For each type of activity, the query should show the total number of individuals who took that type of activity and the average number of individuals taking each type of activity.
Here are my tables :
CREATE TABLE accommodations
(
chalet_number int PRIMARY KEY,
chalet_name varchar(40) NOT NULL,
no_it_sleeps number(2) NOT NULL,
indivppw number(4) NOT NULL
)
CREATE TABLE supervisors
(
supervisor_number int PRIMARY KEY,
supervisor_forename varchar(30) NOT NULL,
supervisor_surname varchar(30) NOT NULL,
mobile_number varchar(11) NOT NULL
)
CREATE TABLE visitors
(
visitor_ID int PRIMARY KEY,
group_ID int NOT NULL,
forename varchar(20) NOT NULL,
surname varchar(20) NOT NULL,
dob date NOT NULL,
gender varchar(1) NOT NULL
)
CREATE TABLE activities
(
activity_code varchar(10) PRIMARY KEY,
activity_title varchar(20) NOT NULL,
"type" varchar(20) NOT NULL
)
CREATE TABLE "groups"
(
group_ID int PRIMARY KEY,
group_leader varchar(20) NOT NULL,
group_name varchar(30)
number_in_group number(2) NOT NULL
)
CREATE TABLE bookings
(
group_ID int NOT NULL,
start_date date NOT NULL,
chalet_number int NOT NULL,
no_in_chalet number(2) NOT NULL,
start_date date NOT NULL,
end_date date NOT NULL,
CONSTRAINT bookings_pk PRIMARY KEY(group_ID, chalet_number));
CREATE TABLE schedule
(
schedule_ID int PRIMARY KEY,
activity_code varchar(10) NOT NULL,
time_of_activity number(4,2) NOT NULL,
am_pm varchar(2) NOT NULL,
"date" date NOT NULL
)
CREATE TABLE activity_bookings
(
visitor_ID int NOT NULL,
schedule_ID int NOT NULL,
supervisor_number int NOT NULL,
comments varchar(200),
CONSTRAINT event_booking_pk PRIMARY KEY(visitor_ID, schedule_ID));
ALTER TABLE visitors
ADD FOREIGN KEY (group_ID)
REFERENCES "groups"(group_ID)
ALTER TABLE Schedule
ADD FOREIGN KEY (activity_code)
REFERENCES activities(activity_code)
ALTER TABLE bookings
ADD FOREIGN KEY (group_ID)
REFERENCES "groups"(group_ID)
ALTER TABLE bookings
ADD FOREIGN KEY (chalet_number)
REFERENCES accommodations(chalet_number)
ALTER TABLE activity_bookings
ADD FOREIGN KEY (visitor_ID)
REFERENCES visitors(visitor_ID)
ALTER TABLE activity_bookings
ADD FOREIGN KEY (schedule_ID)
REFERENCES schedule(schedule_ID)
ALTER TABLE activity_bookings
ADD FOREIGN KEY (supervisor_number)
REFERENCES supervisors(supervisor_number)
I have the following solution:
SELECT activities."type", 'overalltotal' AS OT, ('overalltotal' / 'activities') AS AVG
FROM activities, schedule
WHERE 'overalltotal' = (SELECT SUM(COUNT(schedule_ID))
FROM activities, schedule
WHERE schedule.activity_code = activities.activity_code
GROUP BY activities."type"
)
AND 'activities' = (SELECT COUNT(DISTINCT activities."type")
FROM activities
)
AND schedule.activity_code = activities.activity_code
GROUP BY activities."type";
I have implemented sample data and code to check the variables above:
SELECT SUM(COUNT(schedule_ID))
FROM activities, schedule
WHERE schedule.activity_code = activities.activity_code
GROUP BY activities."type";
Result : 20
SELECT COUNT(DISTINCT activities."type")
FROM activities;
Result : 5
However when running the code :
ORA-01722: invalid number
01722. 00000 - "invalid number"
*Cause:
*Action:
EDIT:
Using Dave's Code i have the following output:
Snowboarding 15
sledding 19
Snowmobiling 6
Ice Skating 5
Skiing 24
How would i do the final part of the question?
and the average number of individuals taking each type of activity.
You must use double quotes around column names in Oracle, not single quotes. For example, "overalltotal". Single quotes are for text strings, which is why you're getting an invalid number error.
EDIT: This is probably the type of query you want to use:
SELECT activities."type", COUNT(*) AS total, COUNT(*)/(COUNT(*) OVER ()) AS "avg"
FROM activities a
JOIN schedule s ON a.activity_code=s.activity_code
JOIN activity_bookings ab ON s.schedule_ID=ab.schedule_ID
GROUP BY activities."type";
Basically, because each activity booking has one visitor id, we want to get all the activity bookings for each activity. We have to go through schedule to do that. They we group the rows by the activity type and count how many activity bookings we have for each type.