Oracle SQL dev, count under heading - sql

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.

Related

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, Using a subquery, List buildings where user has no interest

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.

Find potential duplicate names in database

I have two tables in a SQL Server Database:
Table: People
Columns: ID, FirstName, LastName
Table: StandardNames
Columns: Nickname, StandardName
Sample Nicknames would be Rick, Rich, Richie when StandardName is Richard.
I would like to find duplicate contacts in my People table but replace any of the nicknames with the standard name. IE: sometimes I have Rich Smith other times it is Richard Smith in the People table. Is this possible? I realize it might be multiple joins to the same table but can't figure out how to start.
Firstly, you need to determine how many duplicates you have in your People table...
SELECT p.FirstName, COUNT(*)
FROM People AS p
INNER JOIN StandardNames AS sn
ON CHARINDEX(sn.Nickname, p.FirstName) > 0 OR
CHARINDEX(sn.Nickname, p.LastName) > 0
GROUP BY p.FirstName
HAVING COUNT(*) > 1
That's just to get an idea of what data you're trying to find in relation to the Nicknames that may possibly exist inside (as a wildcard word search) the Firstname and Lastname columns.
If you are happy with the items found then expand on the query to update the values.
Let's say you wanted to change the Firstname to be the Standardname...
UPDATE p2
SET p2.FirstName = p2.Standardname
FROM
(SELECT p.ID, sn.StandardName
FROM People AS p
INNER JOIN StandardNames AS sn
ON CHARINDEX(sn.Nickname, p.FirstName) > 0 OR
CHARINDEX(sn.Nickname, p.LastName) > 0) AS a
INNER JOIN People AS p2 ON p2.ID = a.ID
So this will obviously find all the People IDs that have a match based on the query above, and it will update the People table by replacing the FirstName with the StandardName.
However, there are issues with this due to the limitation of your question.
the StandardNames table should have its own ID field. All tables should have an ID column as its primary table. That's just my view.
this is only going to work for data it matches using the CHARINDEX() function. What you really need is something to find based on a "sound" or similarity to the nicknames. Check out the SOUNDEX() function and apply your logic from there.
And this is assuming your IDs above are unique!
Good luck
You could standardize the names by joining, and count the number of occurrences. Extracting the ID is a bit fiddly, but also quite possible. I'd suggest the following - use a case expression to find the contact with the standard name, and if you don't have one, just take the id of the first duplicate:
SELECT COALESCE(MIN(CASE FirstName WHEN StandardName THEN id END), MIN(id)),
StandardName,
LastName,
COUNT(*)
FROM People p
LEFT JOIN StandardNames s ON FirstName = Nickname AND
GROUP BY StandardName, LastName

Can’t figure out Query and Sub-Queries

I’m having trouble figuring this problem out.
I’m doing some revision exercises for university and would like to understand this BEFORE my exam in 2 days.
I’ve attempted some things (which I’ll post at the end). Please be kind, this is my first Database subject so my attempts may seem very stupid to you.
The question is as follows:
Which artist/s has/have the largest number of shows on at the moment?
Show the First & Last Name of the artist/s and their Address.
ORDER BY clause cannot be used.
Write a single SQL Statement.
Use Sub-Queries.
Relevant tables in the database:
Shows (ShowName, ArtistId, ShowStartDate, ShowEndDate)
Artists (ArtistId, FirstName, FamilyName, Address, PhoneNum)
We assume ArtistId, ShowStartDate, FirstName, FamilyName and Address cannot be null.
Now, I think that I have to count the number of shows each artist has on at the moment. Then, get the ArtistId for the artist/s that has/have the most. Use the ArtistId to retrieve the artist details (names and address).
I got as far as this (which is very wrong):
SELECT FirstName, FamilyName, Address
FROM Artists
WHERE ArtistId = (SELECT ArtistId
FROM Shows
WHERE ArtistId = (SELECT MAX(Counted)
FROM (SELECT ArtistId, COUNT(ArtistId) AS Counted
FROM Shows
WHERE ShowEndDate IS null
GROUP BY ArtistId)
GROUP BY ArtistId));
Well, I know
SELECT ArtistId, COUNT(ArtistId)
FROM Shows
WHERE ShowEndDate IS null
GROUP BY ArtistId
gives me a table with the count of how many times each ArtistId is listed.
Which is good.
But from this results table, I need to get the ArtistId/’s of the ones that have the highest count.
And this is where I’m lost.
Anyone can shed some light?
(As for which DBMS I am using: We have to use one created and supplied by the university. It’s very basic SQL. Simpler than Access 2010).
Thank you
(If you provide an answer [thank you thank you] could you also briefly explain the reasoning behind it?)
You need to find maximum of the count of shows by artist, then find out which artists have that count by re-running the count query but applying a having clause matching the maximum just found.
select FirstName, FamilyName, Address
from Artists
where ArtistId in -- use an in() to select the artists
(select ArtistId from -- just select the artist id from the results
(select ArtistId, count(*) c -- re-run the count query, but see having clause
from Shows
where current_date between ShowStartDate and ShowEndDate
group by ArtistId
having count(*) = -- use a having clause to only select those with the max count
(select max(c) from -- this is simply the maximum count
(select ArtistId, count(*) c -- find all counts by artist
from Shows
where current_date between ShowStartDate and ShowEndDate
group by ArtistId
) counts
)
)
)
Some syntax notes:
count(*) c means the column (with value count(*)) is given the alias c, so it can be referred to by an outer query. You can't refer to it as count(*), because that would be interpreted as an attempt at aggregation.
max(c) gets the maximum of the column named (or aliased) c (AFAIK you can't code max(count(*)) - maybe you could try it - I just typed this in without a console to test it)
counts is a table alias, which is a syntactic requirement when selecting from a result set
You haven't specified which database you're using, so you may have to replace current_date with your database's equivalent.
Some dbs allow you to reuse a query in a query (using a with clause), which would avoid rerunning the count subquery.
This query uses only subselects, but you can do it with a join too.
Try this:
SELECT FirstName, FamilyName, Address
FROM Artists
WHERE ArtistId IN (
SELECT ArtistId
FROM (
SELECT ArtistId, COUNT(ArtistId) AS Counted
FROM Shows
WHERE ShowEndDate IS null
GROUP BY ArtistId) S1
WHERE Counted = (
SELECT MAX(Counted)
FROM (
SELECT ArtistId, COUNT(ArtistId) AS Counted
FROM Shows
WHERE ShowEndDate IS null
GROUP BY ArtistId) S2
GROUP BY ArtistId)
);
It is simple and should work in your case.

How do I establish a SQL query for this many-to-many table?

I'm building this bartering-type function in this site using PHP/MySQL and I'm trying to create a query that responds with the following fields:
owner's username, title, offerer's username, offerer's item
Basically I have three tables here with the following fields:
users
user_id, username, email
items_available
item_number, owner_id (foreign key that links to user_id), title
offers_open
trade_id, offerers_id (fk of user_id), offerers_item(fk with item_number), receivers_id (fk from user_id)
How do I do this? I've seen some references to many-to-many SQL queries but they don't seem to particularly fit what I'm looking for (for example, the offerers_id and the owner_ids refer to different users_id in the Users table, but how do I make them distinguishable in the sql query?)
If I understand correctly, this is what you are looking for:
SELECT owner.username, oferrers.username, ia.title
FROM offers_open o
INNER JOIN users AS offerers
ON o.offerers_id = offerers.user_id
INNER JOIN items_available AS ia
ON o.offerers_item= ia.item_number
INNER JOIN users AS owner
ON ia.owner_id = owner.user_id
I don't see a title on the users table, so didn't include one.
I'm not sure exactly what output you want, but since your users table will appear twice in the query, they need to be aliased like so:
SELECT offerer.username AS offerer_username, title, receiver.username AS receiver_username
FROM users AS owner
JOIN items_available ON owner_id = owner.user_id
JOIN offers_open ON offerers_item = item_number
JOIN users AS receiver ON receivers_id
Again, don't know if that's what you want, but hope you get the idea.
It sounds as you need an alias of the users table.
Something like?
select
u.*, ia.*, oo.*,u2.*
from
users as u,
items_available as ia,
offers_open as oo,
users as u2
where
u.user_id = ia_user_id and
oo.user_id = u2.user_id and
oo.item_id = ia.item_id