Need Help Writing SQL Query in Postgresql - sql

I've been trying to write this query but can't seem to get it right for some reason or another..
What I need to do is:
Change the status of a question to 'closed' if there has not been an update associated with this question inserted into the qUpdateTable in the last 24 hours.
I only want it to be closed if a staff member has replied to it at least once.
You can determine if a staff member or a user has replied to the question by checking the qUpdateTable and seeing if a the StaffID field is empty or has a value for that particular tickets updates. If there is a staffID then it has been updated by a staff member, however if it does not then the qUpdate was done by a user.
Essentialy the way this works is a user posts a question by inserting into the Question table, and replies are made by inserting into the qUpdate table and linked to the original question using the foreign key - "QuestionID".
The tables:
CREATE TABLE Staff
(
ID INTEGER NOT NULL PRIMARY KEY,
Name VARCHAR(40) NOT NULL
);
CREATE TABLE Customer
(
ID INTEGER NOT NULL PRIMARY KEY,
Name VARCHAR(40) NOT NULL,
Email VARCHAR(40) NOT NULL
);
CREATE TABLE Product
(
ID INTEGER NOT NULL PRIMARY KEY,
Name TEXT NOT NULL
);
CREATE TABLE Question
(
ID INTEGER NOT NULL PRIMARY KEY,
Problem VARCHAR(1000),
Status VARCHAR(20) NOT NULL DEFAULT 'open',
Priority INTEGER NOT NULL,
LoggedTime TIMESTAMP NOT NULL,
CustomerID INTEGER NOT NULL,
ProductID INTEGER NOT NULL,
FOREIGN KEY (ProductID) REFERENCES Product(ID),
FOREIGN KEY (CustomerID) REFERENCES Customer(ID),
CHECK (Status IN ('open','closed') AND Priority IN (1,2,3))
);
CREATE TABLE qUpdate
(
ID INTEGER NOT NULL PRIMARY KEY,
Message VARCHAR(1000) NOT NULL,
UpdateTime TIMESTAMP NOT NULL,
QuestionID INTEGER NOT NULL,
StaffID INTEGER,
FOREIGN KEY (StaffID) REFERENCES Staff(ID),
FOREIGN KEY (QuestionID) REFERENCES Question(ID)
);
Some sample inserts:
INSERT INTO Customer (ID, Name, Email) VALUES (1, 'testname1', 'testemail1');
INSERT INTO Customer (ID, Name, Email) VALUES (2, 'testname2', 'testemail2');
INSERT INTO Staff (ID, Name) VALUES (1, 'Don Keigh');
INSERT INTO Product (ID, Name) VALUES (1, 'Xbox');
INSERT INTO Question (ID, Problem, Status, Priority, LoggedTime, CustomerID, ProductID)
VALUES (1, 'testproblem1', 'open', 3, '2012-04-14 09:30', 2, 1);
INSERT INTO Question (ID, Problem, Status, Priority, LoggedTime, CustomerID, ProductID)
VALUES (2, 'testproblem2', 'open', 3, '2012-04-14 09:30', 2, 1);
INSERT INTO qUpdate (ID, Message, UpdateTime, StaffID, QuestionID) VALUES (2, 'testmessage1','2012-07-12 14:27', 1, 1);
INSERT INTO qUpdate (ID, Message, UpdateTime, QuestionID) VALUES (3, 'testmessage1','2012-06-18 19:42', 2);
What I've done so far (which obviously doesn't work)
UPDATE Question
SET Status = 'closed'
WHERE EXISTS
(SELECT qUpdate.QuestionID
MAX(qUpdate.UpdateTime - Now() = INTERVAL '1 day') FROM qUpdate
LEFT JOIN Question ON qUpdate.QuestionID = Question.ID
WHERE qUpdate.StaffID IS NOT NULL);
I realise my explanation may be a bit confusing so if you need more info post and I'll reply ASAP

UPDATE Question
SET Status = 'closed'
where
-- this clause asserts there's at least one staff answer
exists (
select null from qUpdate
where qUpdate.QuestionID = Question.ID
and StaffID is not null
)
-- this clause asserts there's been no update in the last 24 hours
and not exists (
select null from qUpdate
where qUpdate.QuestionID = Question.ID
and qUpdate.UpdateTime > (now() - interval '24 hours')
)
and Status = 'open';
You'll almost certainly want an index on qUpdate(QuestionID) or possibly qUpdate(QuestionID,UpdateTime) or qUpdate(QuestionID,StaffID) to get good performance on the subselects in the exists() tests.

Related

How to reuse value of insert statment

I'm trying to write a SQL statement such that I'm reusing a return value of an insert statement as a value for following insert statement but I have no clue where to start. For example, this is my table schema (didn't write everything).
job {
job_id INT IDENTITY (1, 1) PRIMARY KEY,
start_date,
end_date,
target hours,
worker_id
FOREIGN KEY (worker_id) REFERENCES dbo.worker (worker_id)
}
worker {
worker_id INT IDENTITY (1, 1) PRIMARY KEY,
name
}
And I want to do something like this but I don't think this is the right way to do it
INSERT INTO dbo.job
VALUES(GetDate(), NULL, 8, (
INSERT INTO dbo.worker
OUTPUT
Inserted.worker_id
VALUES ('my_name')
))
Thanks in advance,
best way for your matter is
DECLARE #worker_idtbl TABLE (worker_id INT);
INSERT INTO dbo.worker OUTPUT Inserted.worker_id INTO #worker_idtbl(worker_id) VALUES ('my_name');
INSERT INTO dbo.job VALUES(GetDate(), NULL, 8, (select top 1 worker_id from #worker_idtbl) );

Multi-Query Queries [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
There are several tables in the database: films, persons and creators. Creators has two foreign keys to films and persons, as well as the fields "Character of participation" (director, actor, composer, etc.) and "Role" (see CREATE TABLE statements below). I would like to display a list of films in which the director is at the same time performing one of the main roles, indicating his last name and the role he played.
create table films (
film_id tinyint identity(1, 1),
film_name varchar(20) not null,
film_studio varchar(25) not null,
film_year int not null,
film_country varchar(20) null,
film_length tinyint not null,
film_genre varchar(15) not null,
constraint PK_films primary key(film_id),
);
create table persons (
person_id tinyint identity(1, 1),
person_name varchar(50) not null,
person_bday date not null,
person_dday date,
constraint PK_persons primary key(person_id),
);
create table creators (
creator_id tinyint identity(1, 1),
creator_film tinyint not null,
creator_person tinyint not null,
creator_who varchar(20) not null,
creator_role varchar(20),
constraint PK_creators primary key(creator_id),
constraint FK_CF foreign key(creator_film) references films(film_id),
constraint FK_CP foreign key(creator_person) references persons(person_id),
constraint CH_Who check(creator_who='director' or creator_who='actor' or creator_who='composer'),
);
insert into films(film_name, film_studio, film_year, film_country, film_length, film_genre) values ('Film1', 'Studio1', 2018, 'USA', 100, 'Genre1')
insert into films(film_name, film_studio, film_year, film_country, film_length, film_genre) values ('Film2', 'Studio2', 2018, 'USA', 120, 'Genre2')
insert into films(film_name, film_studio, film_year, film_country, film_length, film_genre) values ('Film3', 'Studio3', 2000, 'England', 90, 'Genre3')
insert into persons(person_name, person_bday, person_dday) values ('John Smitt', '1988-12-12', null)
insert into persons(person_name, person_bday, person_dday) values ('Mel Gibson
', '1988-12-12', null)
insert into persons(person_name, person_bday, person_dday) values ('Miley Cyrus', '2001-12-12', null)
insert into persons(person_name, person_bday, person_dday) values ('Deadpool', '1999-12-12', null)
insert into creators(creator_film, creator_person, creator_who) values (1, 1, 'Director')
insert into creators(creator_film, creator_person, creator_who, creator_role) values (1, 1, 'Actor', 'Main')
insert into creators(creator_film, creator_person, creator_who, creator_role) values (2, 3, 'Actor', 'Secondary')
insert into creators(creator_film, creator_person, creator_who, creator_role) values (3, 4, 'Actor', 'Secondary')
Desired result is: Film1 John Smith Main
http://sqlfiddle.com/#!18/9211f/6
SELECT
films.film_name,
persons.person_name,
actor.creator_role
FROM creators director
INNER JOIN creators actor
ON director.creator_person = actor.creator_person
AND actor.creator_who = 'Actor'
LEFT JOIN films
ON director.creator_film = films.film_id
LEFT JOIN persons
ON director.creator_person = persons.person_id
WHERE director.creator_who = 'Director'

SQL violation of Primary Key constraint on update

--EDITED--
I think I figured out the problem. The original row is being taken to update instead of the latest row therefore the CreationDate is the same and since ID + CreationDate is the primary key it returns a violation. Is there any way to select the latest row instead of the original row when updating records?
Thanks :D
----------------
I got the error violation of primary key constraint but I don't know why because my primary key values are unique.
I can add the record for 'Darren' and update it once. After that I get the error. My trigger works such that when I update an existing record, both the original and edited record are inserted into the table ProcessList so that I am able to see all the changes made to all records.
Tables:
CREATE TABLE dbo.ProcessList
(
TransactionID integer IDENTITY,
IsEdited bit DEFAULT 'FALSE',
ID integer NOT NULL,
Name varchar(30) NOT NULL,
Amount smallmoney NOT NULL,
CreationDate datetime DEFAULT GETDATE(),
ModificationDate datetime,
PRIMARY KEY (ID, CreationDate)
)
CREATE TABLE dbo.ProcessListHist
(
TransactionID integer IDENTITY,
IsEdited bit DEFAULT 'FALSE',
ID integer NOT NULL,
Name varchar(30) NOT NULL,
Amount smallmoney NOT NULL,
CreationDate datetime DEFAULT GETDATE(),
ModificationDate datetime,
PRIMARY KEY (ID, CreationDate)
)
Trigger:
CREATE TRIGGER CloneAfterUpdate ON ProcessList
AFTER UPDATE
AS
IF (UPDATE (Amount) OR UPDATE (NAME))
BEGIN
INSERT INTO ProcessListHist (ID, Name, Amount, CreationDate, ModificationDate, IsEdited)
SELECT
ID, Name, Amount, CreationDate, GETDATE(), 'True'
FROM deleted
UPDATE PL
SET PL.CreationDate = PLH.ModificationDate
FROM ProcessList PL
INNER JOIN deleted ON PL.ID = deleted.ID
AND PL.CreationDate = deleted.CreationDate
INNER JOIN ProcessListHist PLH ON PL.ID = PLH.ID
AND PLH.CreationDate = deleted.CreationDate
INSERT INTO ProcessList (ID, Name, Amount, CreationDate, ModificationDate, IsEdited)
SELECT
ID, Name, Amount, CreationDate, ModificationDate, IsEdited
FROM ProcessListHist
END
Insert/Update statements:
INSERT INTO ProcessList (ID, Name, Amount) VALUES ('1020', 'Darren', '300')
UPDATE ProcessList SET Amount = 1000 WHERE Name = 'Darren'
You logging a transaction on your history table right ? , therefore you need to remove the ID of history table from being unique. Make it TransactionID INT only, not an identity, your problem is because every time you perform an UPDATE , the record is inserted into history table, so if the record already exist meaning to say, if the ID is already existing in the history table , you are not allowed to insert the same ID, that's why you will receiving that error.

Complex SQL Count Query

Hello I've been stuck with one SQL query for my assignment and was hoping for some help.
I need to get the Project ID for the best executed project -the project where (VERY_GOOD record count + GOOD record count) - (VERY_BAD record count + BAD record count) is greatest
My schema and test records in database (HSQLDB)
CREATE TABLE
PROJECT
(
ID IDENTITY NOT NULL PRIMARY KEY,
PROJECT_NAME VARCHAR(255) NOT NULL
);
CREATE TABLE
RECORD
(
ID IDENTITY NOT NULL PRIMARY KEY,
RESULT VARCHAR(255) NOT NULL,
);
CREATE TABLE
RECORD_PROJECT
(
PROJECT_ID INTEGER NOT NULL,
RECORD_ID INTEGER NOT NULL,
PRIMARY KEY(PROJECT_ID, RECORD_ID),
FOREIGN KEY (PROJECT_ID) REFERENCES PROJECT(ID) ON DELETE CASCADE,
FOREIGN KEY (RECORD_ID) REFERENCES RECORD(ID)
);
And test data:
INSERT INTO PROJECT (PROJECT_NAME) VALUES ('Bake a cake');
INSERT INTO PROJECT (PROJECT_NAME) VALUES ('Clean the house');
INSERT INTO RECORD (RESULT) VALUES ('GOOD');
INSERT INTO RECORD (RESULT) VALUES ('VERY_GOOD');
INSERT INTO RECORD (RESULT) VALUES ('VERY_GOOD');
INSERT INTO RECORD (RESULT) VALUES ('BAD');
INSERT INTO RECORD (RESULT) VALUES ('VERY_BAD');
INSERT INTO RECORD_PROJECT (PROJECT_ID, RECORD_ID) VALUES (0,0);
INSERT INTO RECORD_PROJECT (PROJECT_ID, RECORD_ID) VALUES (1,1);
INSERT INTO RECORD_PROJECT (PROJECT_ID, RECORD_ID) VALUES (1,2);
INSERT INTO RECORD_PROJECT (PROJECT_ID, RECORD_ID) VALUES (0,3);
INSERT INTO RECORD_PROJECT (PROJECT_ID, RECORD_ID) VALUES (1,4);
(I removed unrelated fields from tables)
So with this data I have 3 good records and 2 bad, I would need to get the project which has the highest 'rating', which according to this right now would be Clean the house with 3 good ratings over 2 negative for other project.
Maybe someone would figure this out, thanks!
That should be the (not testet) SQL in MySQL-Dialect:
SELECT rp.PROJECT_ID, p.PROJECT_NAME
SUM(CASE WHEN rp.RECORD_ID < 3 THEN 1 ELSE 0 END) AS rating
FROM RECORD_PROJEKT AS rp
JOIN PROJECT AS p ON p.ID = rp.PROJECT_ID
GROUP BY rp.PROJECT_ID
ORDER BY rating DESC

SQL query: Last but one rank for user

My table structure looks like this:
create table rankings (
id IDENTITY NOT NULL,
user_id INT NOT NULL,
game_poule_id INT NOT NULL,
rank INT NOT NULL,
insertDate DATETIME NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (game_poule_id) REFERENCES game_poules(id) ON DELETE CASCADE
);
All old rankings of users per game are saved in this table. Now I want to have the last but one rank in the table for all users in a gamepoule.
Has someone an idea how to achive this? Thanks
You need to self join the table to get the records you require.
For this answer I created your table without the foreign keys as they are not required to get it to work.
CREATE TABLE Rankings (
id int IDENTITY NOT NULL,
user_id INT NOT NULL,
game_poule_id INT NOT NULL,
rank INT NOT NULL,
insertDate DATETIME NOT NULL
);
Insert some sample data. Without more information I cannot simulate any better than this.
INSERT Rankings(user_id,game_poule_id,rank,insertDate)
VALUES(1, 100, 3, CURRENT_TIMESTAMP-2)
INSERT Rankings(user_id,game_poule_id,rank,insertDate)
VALUES(1, 100, 2, CURRENT_TIMESTAMP-1)
INSERT Rankings(user_id,game_poule_id,rank,insertDate)
VALUES(1, 101, 6, CURRENT_TIMESTAMP)
INSERT Rankings(user_id,game_poule_id,rank,insertDate)
VALUES(2, 100, 5, CURRENT_TIMESTAMP-2)
INSERT Rankings(user_id,game_poule_id,rank,insertDate)
VALUES(2, 100, 1, CURRENT_TIMESTAMP-1)
INSERT Rankings(user_id,game_poule_id,rank,insertDate)
VALUES(2, 101, 2, CURRENT_TIMESTAMP)
Query for the last but one rank
SELECT Rankings.game_poule_id, Rankings.user_id, rank, MAX(Rankings.insertDate)
FROM Rankings INNER JOIN
(SELECT game_poule_id, user_id, MAX(insertDate) max_insert_date
FROM rankings
GROUP BY game_poule_id, user_id) Max_Ranking_Date
ON Rankings.user_id = Max_Ranking_Date.user_id
AND Rankings.insertDate < Max_Ranking_Date.max_insert_date
AND Rankings.game_poule_id = Max_Ranking_Date.game_poule_id
GROUP BY Rankings.game_poule_id, Rankings.user_id, rank
PLEASE NOTE!
As you can see from the results you will not get a ranking for a game that only has one row per user. But since you are asking for the "last but one" that only makes sense for games with multiple entries.
EDIT:
I've just realised the query I have provided will not return one row per user per game. Anyone want to fix it? I have to get on with some work :)
Another possible (not very nice) solution
SELECT
*
FROM
rankings r
WHERE
FK_gamePoule = 0 AND
r.insertDate = COALESCE(
(SELECT
r2.insertDate
FROM
rankings r2
WHERE
r.FK_user = r2.FK_user ORDER BY r2.insertDate DESC
LIMIT 1
OFFSET 1), '2048-12-31 23:59:59')