Oracle SQL generate query - sql

Following is my table schema.
Channel listing table:
CHAN_NUMBER CHAN_NAME CHAN_TYPE
----------- -----------------------------------
1 MTV Music
2 ESPN Sports
3 TNT Movies
4 Fox Movies
5 Fox Sports
customer survey table:
SURV_ID SURV_DATE SURV_FAV_CHAN CUST_NUMBER
---------- --------- ------------- -----------
1 25-NOV-12 1 2
2 24-NOV-12 2 1
3 24-NOV-12 3 3
4 24-NOV-12 4 4
5 24-NOV-12 5 5
6 24-NOV-12 1 6
7 24-NOV-12 2 7
8 24-NOV-12 3 8
9 24-NOV-12 4 9
10 24-NOV-12 5 10
11 24-NOV-12 1 11
I have these two tables that I need to generate a report that lists every channel and a count of how many customers have selected that channel as their favorite.
On oracle database I got up to the point where I am generating a count of each time a channel was selected as a favorite from the SURVEY table. But I can't figure out how to join them to create a list of channels displaying the channel number, the name and the count of customers who chose it as their favorite.
-- my channel table query
SELECT CHAN_NUMBER, CHAN_NAME FROM CHANNEL;
-- here is how I'm generating the couNt
SELECT COUNT(SURV_FAV_CHAN) FROM SURVEY
GROUP BY SURV_FAV_CHAN HAVING COUNT(SURV_FAV_CHAN) > 1;
ANY HELP WOULD BE AWESOME.

Please check this reference * SQLFIDDLE
You said you want list every channel, and count of how many customers have selected that channel as their favourite.
Let's go from nested to outside. Nested query you count number of customers from Survery table grouping by favourite channel. Every channel means, you need to do a LEFT JOIN on Channels table to get all the records.
Query:
(select c.*, s.ct from
channel c
left join
(select count(cust_number) as ct
, surv_fav_chan from survey
group by surv_fav_chan) as s
on c.chan_number = s.surv_fav_chan
;
Results:
CHAN_NUMBER CHAN_NAME CHAN_TYPE CT
1 MTV Music 3
2 ESPN Sports 2
3 TNT Movies 2
4 Fox Movies 2
5 Fox Sports 2
You seem to treat FOX as two channels offering two different types of programmes. So I have left it as it is. If you want to even count customers by channel type then please clarify.
PS: You may ignore the other old table schema in that SQLFIDDLE table sample. NOTE that it is in MYSQL, however this is an ANSI query - so you may apply it to ORACLE as well.

You can try something like this:
SELECT MAX(CH.CHAN_NUMBER), MAX(CH.CHAN_NAME), COUNT(SRV.SURV_FAV_CHAN) FROM SURVEY SRV
LEFT JOIN CHANNEL CH ON CH.CHAN_NUMBER = SRV.SURV_FAV_CHAN
GROUP BY SRV.SURV_FAV_CHAN HAVING COUNT(SRV.SURV_FAV_CHAN) > 1;
And you may want to use SUM(SRV.SURV_FAV_CHAN) if you really need the total amount of customers if I understand you question correctly

Assuming that SURV_FAV_CHAN and CHAN_NUMBER is the relation, use that for your JOIN, so try this:
SELECT CHAN_NUMBER
, CHAN_NAME
, COUNT(DISTINCT SURVEY.CUST_NUMBER) AS FAV_CHANNEL_CNT
FROM CHANNEL
LEFT JOIN SURVEY
ON SURVEY.SURV_FAV_CHAN = CHANNEL.CHAN_NUMBER
GROUP BY CHAN_NUMBER, CHAN_NAME

Related

How can i solve blank spots in a SQL View?

In my sqllite-excercises i have discovered the following problem:
I basically have three different Tables:
Subjects
PRIMARY KEY(ID)
Subject
1
Business
2
IT
3
Sports
Participants
PRIMARY KEY(ID)
Name
semester
1
Meyer
6
2
Smith
4
3
Brown
4
4
White
2
5
Anthonie
2
6
Frankson
2
They are referenced in the Table participants List
SUBJECT.ID
Participant.ID
1
2
1
3
1
5
2
4
2
6
3
1
Now im supposted to create a VIEW that contains: The Participants.ID, Participants.Name and Subjects.Subject so i have a Table that shows the ID, the Name and the Subject the participant is visiting.
So far I did this:
CREATE VIEW[OVERVIEW]AS
SELECT Participants.ID,
Participants.Name,
Subjects.Subject
from Participants
LEFT JOIN Subjects on Participants.ID = Subjects.ID;
As a result i get this:
Participants.ID
Participant.Name
Subjects.Subject
1
Meyer
Business
2
Smith
IT
3
Brown
Sports
4
White
None
5
Anthonie
None
6
Frankson
None
And it makes sense since there are only three Subjects and i Leftjoined 6 Participants.ID on only 3 Subjects.Subject
How can i fill out the blank Subjects? So that the subjects for 4-6 are shown aswell?
I hope you can understand my problem and i declared it good enough.
You can't join Participants to Subjects because they are not directly related, so this ON clause:
on Participants.ID = Subjects.ID
does not make sense because the IDs of participants are not related to the IDs of the subjects.
You have the table ParticipantsList that can be used as an intermediate link between the other 2 tables:
SELECT p.ID, p.Name, s.Subject
FROM Participants p
LEFT JOIN ParticipantsList pl ON pl.Participant_ID = p.ID
LEFT JOIN Subjects s ON s.ID = pl.Subject_ID;
This will return all participants, even if they are not linked to any subject.
If you want only the participants for which there is at least 1 subject in the table ParticipantsList then you can use INNER joins.
For the sample data that you provide in your question in both cases the results are the same.
See the demo.

SQL Calculations With Multi-Group Affiliations

I'm attempting to have a function or view that is able to calculate and roll up various counts while being able to search on a many to many affiliation.
Here is an example data set:
Invoice Table:
InvoiceID LocationID StatusID
1 5 1
2 5 1
3 5 1
4 5 2
5 7 2
5 7 1
5 7 2
Group Table:
GroupID GroupName
1 Group 1
2 Group 2
GroupToLocation Table:
GroupToLocationID GroupID LocationID
1 1 5
2 2 5
3 2 7
I have gotten to the point where I could sum up the various statuses per location and get this:
LocationID Status1 Status2
5 3 1
7 1 2
Location 5 has 3 Invoices with a status of 1, and 1 invoice with a status of 2 while Location 7 has 1 status 1 and 2 status 2
There are two groups, and Location 5 is in both, while Location 7 is only in the second. I need to be able to set it up where I can append a where statement like this:
select * from vw_GroupCounts
where GroupName = 'Group 2'
or
select Invoice, SUM(*) from vw_GroupCounts
where GroupName = 'Group 2'
And that result in only getting Location 7. Whenever I do this, as I have to use left joins or something along those lines, the counts are duplicating for each group the the Location is affiliated with. I know I could do something along the lines of a subquery and pass in the GroupName into that, but the system I am working with uses a dynamic query builder that appends WHERE statements based on user input.
I don't mind using view, or functions, or any number of functions inside of functions, but I hope there is a way to do what I'm looking for.
Since locations 5 and 7 are in Group 2, if you search for group 2 in the where clause after joining all the tables, then you would get all records in this case, this isn't duplication, just the way the data is. A different join wouldn't change this, only changing the data. Let me know if I am misunderstanding something though.
Here is how you would join them to do that search.
Here it is with your first example of the location and status count.

How do I add rows in one table in specific conditions?

I work on an Oracle database.
I have a table (it is a join table) but this is how it looks:
CustomerID days_attached Startdate enddate team
1 7 01-01-2016 08-01-2016 A
1 2 09-01-2016 10-01-2016 B
1 8 01-02-2016 09-02-2016 A
2 1 01-02-2017 02-02-2016 C
2 8 08-05-2017 16-05-2017 C
I need to know how long a person is attached to a specific team. A person can be attached to a person for a X amount of days. That person could be in a team. For instance in this case, how long is a person attached to team A = 7+8 15 days.
How do I get this in a SQL statement?
Our app only supports SQL not PL/sql .
I expect an output like:
CustomerID days_attached team
1 15 A
1 2 B
2 9 C
select customer, team, sum(dayattached) from table_name group by customer, team
hopefully this will help u

SQL 3 table Join While taking all values from 1 table but only filled from other 2

I have three tables: the first has a list of category IDs, the second has dataset information, and the third has import information.
What I have
select dataset.pc_id , count(*)
from import
join dataset on CAST (dataset.internal_id as varchar(20)) = import.product_id
group by dataset.pc_id, order by pc_id asc
This will output:
3 4
4 5
6 200
7 192
8 1000
Where product_category comes into play is this: I want the output to look like:
1 0
2 0
3 4
4 5
6 200
...
16 0
The 16 are the number of different product categories from the product_category table that I currently cannot figure out how to fit into that statement.
What is the way to get all the id's from product category into this list with the information joined occupying the result?
Figured it out, needed to get rid of selecting dataset.pc_id and just go with product_category.id and then right join product_category.

linked tables in firebird, discard records that have a specific value in a one to many linked table

I have two tables in a firebird 1.5 database, the tables are client and notes, in the notes table there can be multiple records for each corresponding record in Client table, and sometimes none.
The tables are structured like
Client
Client_id name
-----------------
1 Sam
2 Lee
3 Steve
4 Linda
5 Sue
6 Jill
7 Jack
Notes
Notes_id client_id Note
------------------------------
1 1 New
2 1 do not send
3 2 old
4 2 likes
5 4 do not send
6 5 new
7 5 Cats and Dogs
8 5 drives
I would like to run a select statement that would only return records from the Client table where there is no note named ‘do not send’ linked to the client in the notes table. So with the above examples the select statement would only return the following records from the client table.
Client_id name
-----------------
2 Lee
3 Steve
5 Sue
6 Jill
7 Jack
Is this possible? Any assistance with this would be appreciated.
Regards Alan
Below are three queries that will do the task:
SELECT
c.*
FROM
client c
WHERE
NOT EXISTS(SELECT * FROM notes n WHERE n.client_id = c.client_id
AND n.note = 'do not send')
or
SELECT
c.*, n.client_id
FROM
client.c LEFT JOIN
(SELECT client_id FROM notes WHERE note = 'do not send') n
ON c.client_id = n.client_id
WHERE
n.client_id IS NULL
or
SELECT
c.*
FROM
client c
WHERE
NOT c.client_id IN (SELECT client_id FROM notes n
WHERE n.note = 'do not send')