oracle sql dev, Using a subquery, List buildings where user has no interest - sql

I am currently trying to get the database to list a buildings, BuildingNum, BuildingName and instname that have a user who has not Interest(interest.description = null).
(PK) = Primary Key
(FK) = Foreign Key
The database schema is as follows:
Building(buildingNum(PK), Description, instname, buildName, state, postcode)
User(UNum(PK), buildingNum(FK), Surname, FirstName, initials, title)
File(FileNum(PK), title)
UserAccount(FileNum(PK)(FK), UNum(PK)(FK))
Job(JobNum(PK), id, title)
Interest(JobNum(PK)(FK), UNum(PK)(FK), Description)
So far i have tried the following block of code:
select B.buildingNum, B.BuildName, B.instname
from Building B join User U
where B.deptNum = U.deptNum in (select I.Description
from interest I
where description = null);
I'm struggling with how to do this using a sub query, all i receive is an error as this doesn't work. Im not sure if i should be using the join like that or if i have added the subquery correctly. Thanks to anyone who can help.

If you want no interests, use exists:
select b.buildingNum, b.BuildName, b.instname
from Building b
where exists (select 1
from users u left join
interest i
on i.unum = u.unum
where b.deptNum = u.deptNum and
i.unum is null -- no interests
);
The subquery returns users (in a given building) that have no interests. The exists is simply saying that at least one exists.
As a note: = null is never used for comparisons. It never returns a true value. The correct syntax is is null.

Related

Delete entry from 2 tables

I got 2 tables:
STUDENT (ID, name, surname, class)
SCORES (student_id, score_date (you can choose a date format), score , discipline)
I want to delete student Ionescu(and related entries from Score table)
I tried this
DELETE SCORE,STUDENT FROM STUDENT INNER JOIN SCORE
WHERE Score.StudentID=Student.Id
AND Student.Name = 'Ionescu';
and it's not working. How can I fix it?
You can delete the entries one by one, like this:
DELETE FROM SCORE WHERE score.StudentID in (select id from student where student.name = 'Ionescu');
This also makes the SQL-Query easier to read :-)
Ideally, you used the "ON DELETE CASCADE"-clause when creating the SCORE-Table - this would allow you to not worry about that SQL at all anymore, because the related entry will be deleted automatically as well. - Check this site for more Informations about Cascade: https://kb.objectrocket.com/postgresql/how-to-use-the-postgresql-delete-cascade-1369
You might want to consider a cascading delete constraint. But in the meantime, you can do this in one statement using returning:
with d as (
delete from student s
where s.name = 'Ionescu'
returning *
)
delete from score sc
where sc.studentid in (select d.id from d);

Oracle SQl Dev, display id, firstname, surname and users number of files

I am trying to write a query in oracle sql developer that will list
UNum, FirstName, Surname, and the number of files the users has, if the user has 0 it should be displayed as 0 next to their name.
(PK) = Primary Key
(FK) = Foreign Key
The database schema is as follows:
Building(buildingNum(PK), Description, instname, buildName, state, postcode)
User(UNum(PK), buildingNum(FK), Surname, FirstName, initials, title)
File(FileNum(PK), title)
UserAccount(FileNum(PK)(FK), UNum(PK)(FK))
Job(JobNum(PK), id, title)
Interest(JobNum(PK)(FK), UNum(PK)(FK), Description)
So far i have tried the following block of code:
Select User.UNum, User.FirstName, User.Surname, Count(UserAccount.FileNum)
from User, UserAccount
where User.UNum = UserAccount.UNum
group by User.UNum, User.FirstName, User.Surname;
I end up with the result being a long list of Users made up of UNum, FirstName and Surname followed by the number of files they have, however none of the results return with a 0. the list also seems to be extremely long for the size of the database. How do i find those who also have 0 files and is there anything else im doing wrong? expected result should be a much shorter list of users including those who don't have any files (There are 7 people in the database with 0 files) Thanks.
You want a left join:
Select u.UNum, u.FirstName, u.Surname,
Count(ua.FileNum)
from User u left join
UserAccount ua
on u.UNum = ua.UNum
group by u.UNum, u.FirstName, u.Surname;
This also introduces table aliases, which makes it simpler to write and read the queries.
You can also write this using a correlated subquery:
select u.UNum, u.FirstName, u.Surname,
(select count(ua.FileNum)
from UserAccount ua
where u.UNum = ua.UNum
)
from User u;
This version might have somewhat better performance.
You want a left join. That keeps rows from the table left of the join operator even if no matching row is found in the table right to it.
SELECT user.unum,
user.firstname,
user.surname,
count(useraccount.filenum)
FROM user
LEFT JOIN useraccount
ON useraccount.unum = user.unum
GROUP BY user.unum,
user.firstname,
user.surname;

Oracle SQL dev, count under heading

I am currently trying to get the database to list a interest job number, and users title and count the users interested in the interest description. The query is meant to count under the heading "No. Users Interested. Interests with no interested users should be excluded.
(PK) = Primary Key
(FK) = Foreign Key
The database schema is as follows:
Building(buildingNum(PK), Description, instname, buildName, state, postcode)
User(UNum(PK), buildingNum(FK), Surname, FirstName, initials, title)
File(FileNum(PK), title)
UserAccount(FileNum(PK)(FK), UNum(PK)(FK))
Job(JobNum(PK), id, title)
Interest(JobNum(PK)(FK), UNum(PK)(FK), Description)
So far i have tried the following block of code:
select I.JobNum, U.title, count(I.description) AS 'No. Academics Interested'
from Interest I join Users U
where U.UNum = I.UNum AND I.description != null;
I'm struggling with how to do this using a sub query, all i receive is an error as this doesn't work. I'm not sure of how I do the Count(I.description) under a heading and how i should be doing it. Thanks to anyone who can help.
You presumably would need to aggregation using GROUP BY here:
SELECT
i.JobNum,
u.title,
COUNT(i.description) AS "No. Academics Interested"
FROM Interest i
LEFT JOIN Users u
ON u.UNum = i.UNum
GROUP BY
i.JobNum,
u.title;
Note that the check I.description != null (which should actually be i.description IS NOT NULL) is not necessary here, because the COUNT function by default does not count NULL values.

How to make all rows in a table identical which the exception of 1 field?

I am trying to make it so all the users have the same items because I am doing an experiment with my app and need the experimental control of flattened data.
I used the following SQL statement in my last attempt:
insert into has (email,id,qty,price,item_info,image)
select 'b#localhost.com',id,qty,price,item_info,image
from
(
select * from has
where email != 'b#localhost.com'
) as o
where o.id not in
(
select id from has
where email = 'b#localhost.com'
);
This should add all items which 'b#localhost.com' does not already have but other users do have, to 'b#localhost.com's inventory. (the 'has' table)
However, I get the following error:
The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index
I understand what this error means, but I do not understand why it is occurring. My statement inserts all records which that email doesn't already have, so there should not be any duplicate id/email pairs.
The database structure is shown below, circles are attributes, squares are tables, and diamonds are relationship sets. The HAS table is a relationship set on USER_ACCOUNT and ITEM, where the primary keys are email and id respectively.
Please try the following...
INSERT INTO has ( email,
id,
qty,
price,
item_info,
image )
SELECT a.email,
b.id,
a.qty,
a.price,
a.item_info,
a.image
FROM has a
CROSS JOIN has b
JOIN
(
SELECT email,
id
FROM has
) c ON a.email = c.email AND
b.id <> c.id;
The CROSS JOIN appends a copy of each row of has to each row of has. Please see http://www.w3resource.com/sql/joins/cross-join.php for more information on CROSS JOIN's.
Each row of the resulting dataset will have two id fields, two email fields, two qty fields, etc. By giving each instance of has an alias we create the fields a.id, b.id, a.email, etc.
We then compare each combination of "old" email address and "new" id to a list of existing email / id combinations and insert the old values with the new id replacing the old one into has
If you have any questions or comments, then please feel free to post a Comment accordingly.
Further Reading
http://www.w3resource.com/sql/joins/cross-join.php for more information on CROSS JOIN's
https://www.w3schools.com/sql/sql_in.asp for more information on WHERE's IN operator
https://www.w3schools.com/sql/sql_groupby.asp for more information on GROUP BY
I think the issue here is not that the code is trying to insert something which already exists, but that it's trying to insert more than one thing with the same PK. In lieu of an response to my comment, here is one way to get around the issue:
INSERT INTO has (email,id,qty,price,item_info,image)
SELECT
'b#localhost.com',
source.id,
source.qty,
source.price,
source.item_info,
source.image
FROM
(
SELECT email, id, qyt, price, item_info, image FROM has
) as source
JOIN
(
SELECT min(email) as min_email, id FROM has GROUP BY by id)
) as filter ON
filter.min_email = source.email
WHERE
source.id not in
(
SELECT id from has WHERE email = 'b#localhost.com'
);
The key difference from your original code is my extra join to the subquery I've aliased as filter. This limits you to inserting the has details from a single email per id. There are other ways to do the same, but I figured that this would be a safe bet for being supported by Derby.
I removed the WHERE clause from the source sub-query as that is handled by the final WHERE.

SQL Update one table comparing info from two tables

I have the following problem:
Let's suppose I defined TWO tables
USERS
ID (int. key)
NAME (String)
SALARY (currency)
USERSADD
ID (int. key)
TYPE (String)
The 2nd table stores additional information for USERS. Obviously the real tables are more complicated but this is the idea. (Don't ask me why another table is created instead of adding fields to the first table, this is my boss's idea).
Now I am trying to UPDATE the first table if a condition from second table is satisfied.
Something like this:
UPDATE USERS U, USERSADD A
SET U.SALARY = 1000
WHERE U.ID = A.ID
AND A.TYPE = 'Manager'
In Netbeans Derby I have an error: ", found in column X", and it refers to the comma between the two tables (UPDATE USERS U, USERSADD A). I hope I was clear enough...
Would somebody be kind enough to provide me with a solution? Thanks in advance.
UPDATE USERS
SET SALARY = 1000
WHERE ID IN (
SELECT ID FROM USERSADD
WHERE TYPE = 'Manager')
UPDATE USERS
SET USERS.SALARY = 1000
FROM USERS JOIN USERSADD ON USERS.ID = USERSADD.ID
WHERE USERSADD.TYPE ='MANAGER'
The syntax you are using uses an implicit INNER JOIN. It would be better for you to use an explicit join. Try something like this:
UPDATE Users
SET Salary = 1000
FROM Users u
INNER JOIN Usersadd a on u.id=a.id
AND a.Type = 'Manager
UPDATE USERSU
SET SALARY = 1000
WHERE exist IN (
SELECT ID
FROM USERSADD A
WHERE TYPE = 'Manager'
AND U.id = A.id
)