SQL*Plus query: table joins with aggregation - sql

CREATE TABLE users
()
CREATE TABLE avatars
()
CREATE TABLE weapons
()
I need two queries for these tables that I created and I am having trouble doing it, any help would be greatly appreciated.
For all Avatars produce a list showing the avatar name, the total number of weapons it currently holds and the total cost of all weapons currently held. I want no more extra information shown apart from these three main pieces, so I need to get information from table 2 and 3.
For any given User email (i.e. entered at runtime) list the owned Avatar names in reverse order of date of birth and the weapons (including weapon name, range and cost) held by that Avatar.
Any help would be greatly appreciated. I am using SQL*Plus. The tables are not very efficient so any improvements would be welcomed but mainly I need help with these queries.

select
max(a.name),
count(1),
sum(w.cost)
from
avatars a
inner join weapons w on w.weapon_id=a.no_wp_id
group by
a.no_wp_id
;
select
a.name,
w.weapon_name,
w.range,
w.cost
from
users u
inner join avatars a on a.user_id=u.id
inner join weapons w on w.weapon_id=a.no_wp_id
where
u.email='given#email.com'
order by
a.dateOfBirth desc
;
If your queries depend on email being unique, you should have a unique key on it.
Your weapons table does not appear to have a range column on it, but you implied it does in your requirement for query #2. I've included w.range anyway.
In avatars, no_wp_id should probably be named something like avatar_id or just id, and in weapons, weapon_id should be named avatar_id.
You should go through an SQL tutorial. Here's one: http://www.tutorialspoint.com/sql/sql-overview.htm.

Related

How to design a query in WHERE clause of all column that contain same data value?

I have a table, the columns are:
Respondent_ID, classical, gospel, pop, kpop, country, folk, rock, metal ... (all genre of music)
there are 16 columns of different type of genre of music,
and data value is Never, Rarely, Sometimes or Very frequently
SELECT *
FROM genre_frequency
WHERE
I want to design a query which show results of all columns in the table what has the value 'Very Frequently', can anyone lend me a hand here? I'm still new to this, please help anyone...
Could put the same criteria under every genre field with OR operator - very messy. Or could use a VBA custom function.
Or could normalize data structure so you have fields: RespondentID, Genre, Frequency. A UNION query can rearrange data to this normalized structure (unpivot). There is a limit of 50 SELECT lines and there is no builder or wizard for UNION - must type or copy/paste in SQL View.
SELECT Respondent_ID, "classical" AS Genre, classical AS Frequency FROM genre_frequency
UNION SELECT Respondent_ID, "gospel", gospel FROM genre_frequency
... {continue for additional genre columns};
Now use that query like a table in subsequent queries. Just cannot edit data.
SELECT * FROM qryUNION WHERE Frequency="Very frequently";
UNION query can perform slowly with very large dataset. Probably would be best to redesign table. Could save this rearranged data to a table. If you want to utilize lookup tables for Genre and Frequency in order to save ID keys instead of full descriptive text, that can also be accommodated in redesign.
You should normalize your schema. This one has the problem that it requires you to alter the table whenever you want to add or remove a genre.
You must have at least three tables:
Table Respondent: Respondent_ID (PK), Name, etc.
Table Genre: Genre_ID (PK), Name
Table Respondent_Genre: Respondent_ID (PK, FK), Genre_ID (PK, FK), Frequency
This also easily allows you to alter the name of a genre or to add additional attributes to a genre like sub-genre or an annotation like (1930–present).
Optionally, you could also have a lookup table for Frequencies and then include the Frequency_ID in Respondent_Genre instead the Frequency as text.
Then you can write a query like this
SELECT r.Name, g.Name, rg.Frequency
FROM
(Respondent r
INNER JOIN Respondent_Genre rg
ON r.Respondent_ID = rg.Respondent_ID)
INNER JOIN Genre g
ON rg.Genre_ID = g.Genre_ID
WHERE
rg.Frequency = 'Very Frequently'

Insert columns from two tables to a new table in PostgreSQL

I am building an application to manage an inventory and I have a problem when creating my tables for the database (I am using PostgreSQL). My problem is the following:
I have two tables, one called 'products' and one called 'users'. Each one with its columns (See image). I want to create a third table called 'product_act_register' , which will keep a record of activity of the products and has with it the columns id, activity_type, quantity, date. But, I want to add other columns which are taken from the table 'users' and 'products'.
It should look like this (Image)
Where product_id, product_name, product_category, product_unit are taken from the table 'products' and the column 'user_id' is taken from the table 'users'.
How can I do this with PostgreSQL ?
Your description and your precise goals are very unclear. You didn't tell us what should happen in the different cases (only a product exists or only a user exists or none exist or both exist). You also didn't tell us how the other columns not coming from these tables should be filled. You furthermore didn't tell us how the tables users and products depend on each other. Basically you con do something like this if you only want to do an insert if both tables have an entry:
INSERT INTO product_acts_register
SELECT 1,'ActivityType1',p.id, p.name, p.category,
p.unit, u.id, 100, CURRENT_DATE
FROM products p JOIN users u ON p.id = u.id;
(Since you didn't tell us how or if to join them, I assumed to join on their id column)
If you don't care about this, but want to insert an entry for any possible combination of users and products, you can just select both tables without joining:
INSERT INTO product_acts_register
SELECT 1,'ActivityType1',p.id, p.name, p.category,
p.unit, u.id, 100, CURRENT_DATE
FROM products p, users u;
You can replicate this here and try out other commands: db<>fiddle
Please be more precise and give us more information when asking the next question.

Oracle Apex count and display number of entries in a column

I have a table in Oracle Apex populated with contacts and their information. On the dashboard of my app, I'd like it to say how many contacts are in the database using the big list of values plug-in or something like that. I'm using the following code:
select contact_ID, count(*)
from
contacts
group by contact_id
However all I'm getting is the number of times each specific contact appears in the table (which is 1), instead of the total number of contacts. I understand what I did wrong in the code, but I'm not sure how to fix it.
For further information, the table columns are very basic, just 'Name', 'contact_id' (the primary key), 'Phone_Number', and so on. The table is called CONTACTS.
I'm also looking to eventually have the total number of organizations and comments on the dashboard as well.
Thanks!
Try
SELECT
COUNT(mycolumn) AS d,
COUNT(mycolumn) AS r
FROM
mytable
I think you just want count(*):
select count(*)
from contacts;
Presumably, contactID is unique in a table called contacts.

SQL: How do I find which movie genre a user watched the most? (IMDb personal project)

I'm currently working on a personal project and I could use a little help. Here's the scenario:
I'm creating a database (MS Access) for all of the movies myself and some friends have ever watched. We rated all of our movies on IMDb and used the export feature to get all of the movie data and our movie ratings. I plan on doing some summary analysis on Excel. One thing I am interested in is the most common movie genre that each person watched. Below is my current scenario. Note that the column "const" is the movies' unique IDs. I also have individual tables for each person's ratings and the following tables are the summary tables that make up the combination of all the movies we have watched.
Here's the table I had: http://imgur.com/v5x9Dhg
I assigned each genre an ID, like this: http://imgur.com/aXdr9XI
And here is a table where I have separate instances for each movie ID and a unique genre: http://imgur.com/N0wULo8
I want to find a way to count up all of the genres that each person watches. Any advice? I would love to provide any additional information that you need!
Thank you!
You need to have at least one table which has one row per user and const (movie watched). In the 3 example tables you posted nothing shows who watched which movies, which is information you need to solve your problem. You mention having "individual tables for each person's ratings," so I assume you have that information. You will want to combine all of them though, into a table called PERSON_MOVIE or something of the like.
So let's say your second table is called GENRE and its columns are ID, Genre.
Let's say your third table is called GENRE_MOVIE and its columns are Const and ID (ID corresponds to ID on the GENRE table)
Let's say the fourth table, which you did not post, but which is required, is called PERSON_MOVIE and its columns are person, Const, rating.
You could then write a query like this:
select vw1.*, ge.genre
from (select um.person, gm.id as genre_id, count(*) as num_of_genre
from user_movie um
inner join genre_movie gm
on um.const = gm.const
group by um.person, gm.id) vw1
inner join (select person, max(num_of_genre) as high_count
from (select um.person, gm.id, count(*) as num_of_genre
from user_movie um
inner join genre_movie gm
on um.const = gm.const
group by um.person, gm.id) x
group by person) vw2
on vw1.person = vw2.person
and vw1.num_of_genre = vw2.high_count
inner join genre ge
on vw1.genre_id = ge.id
Edit re: your comment:
So right now you have multiple tables reflecting people's ratings of movies. You need to combine those into a table called PERSON_MOVIE or something similar (as in example above).
There will be 3 columns on the table: person, const, rating
I'm not sure if access supports the traditional create table as select query but ordinarily you would be able to construct such a table in the following way:
create table person_movie as
select 'Bob', const, [You rated]
from ratings_by_bob
union all
select 'Sally', const, [You rated]
from ratings_by_sally
union all
select 'Jack', const, [You rated]
from ratings_by_jack
....
If not, just combine the tables manually and add a third column as shown indicating what users are reflected by each row. Then you can run my initial query.

Oracle 10g - Linking two views with different user privileges

I am new to this, so I apologise if I am not completely clear...
Background:
Ten staff members, all with the role Teacher assigned to them.
The StaffDetails table has 6 columns - StaffID, StaffName, DateOfBirth, Gender, HolidayDaysRemaining & StaffRole
I would like the teachers to see all of their own details, but only the StaffID, StaffName and StaffRole columns of other members of staff.
The code I already have is explained below:
Firstly, a view that shows the three columns that all staff members can see (StaffID, StaffName, StaffRole):
CREATE VIEW StaffDetailsForStaffMutual AS
SELECT sd.StaffID, sd.StaffName, sd.StaffRole
FROM StaffDetails sd;
Secondly, a view that will hold the columns DateOfBirth, Gender, and HolidayDaysRemaining. These will only be viewable by the person logged in (as shown by sub-query). The StaffID attribute is only included so that a common column is in both views - it will be present only once in the final table.
CREATE VIEW StaffXDetailsForStaffX AS
SELECT sd.StaffID, sd.DateOfBirth, sd.Gender, sd.HolidayDaysRemaining
FROM StaffDetails sd
WHERE StaffID IN
(SELECT USER
FROM DUAL);
My problem is, is that I cannot find a way to join these two views to make a single table. In a perfect world, if a staff member with ID 301 logged on and queried the whole of the table, it would display six columns, the first row would have all of their data in, the second row would have three columns of StaffID 302's data in and so on and so forth.
Any help here would be greatly appreciated!
(Finally, just to show that I've had a go, I tried this query:
CREATE VIEW StaffDetailsForStaff AS
SELECT sdfsm.StaffID, sdfsm.StaffName, sdfsm.StaffRole,
sxdfsx.DateOfBirth, sxdfsx.Gender, sxdfsx.HolidayDaysRemaining
FROM StaffDetailsForStaffMutual sdfsm, StaffXDetailsForStaffX sxdfsx
WHERE sdfsm.StaffID = sxdfsx.StaffID;
but when logged on as 301 and queried, it showed only 301's data and no-one else's!)
You probably need an outer join
CREATE VIEW StaffDetailsForStaff AS
SELECT sdfsm.StaffID, sdfsm.StaffName, sdfsm.StaffRole,
sxdfsx.DateOfBirth, sxdfsx.Gender, sxdfsx.HolidayDaysRemaining
FROM StaffDetailsForStaffMutual sdfsm LEFT JOIN StaffXDetailsForStaffX sxdfsx
ON sdfsm.StaffID = sxdfsx.StaffID;