I can not just join it because I need to group DVDs by movie_id first? - ORACLE - oracle11g

I have this query that has no problem:
SELECT m.movie_name, cd.times_requested
FROM movie m,
(select *
from(
select movie_id, count(movie_id) as times_requested
from movie_queue
where status_id=0 or status_id=1
group by movie_id
) ab
where times_requested>1) cd
WHERE m.movie_id=cd.movie_id;
It returns the following list.
MOVIE_NAME TIMES_REQUESTED
----------------------------------------------------------------------
E.T. the Extra-Terrestrial 2
Indiana Jones and the Kingdom of the Crystal Skull 2
War of the Worlds 3
Unbreakable 3
Question:
How do I add another column showing the amount of DVDs available for each movie, I can not just join it because I need to group DVDs by movie_id first?.
Table above is OK, but I want to add a third column, the third column will contain information about the number of DVDs available for each movie. the problem is that the number of dvds is stored in another table call DVDS. The structure of the table DVDs is similar to this:
DVD_ID MOVIE_ID DVD_ENTRY_DATE
---------- ---------- --------------
1 1 24-JUL-12
2 1 24-JUL-12
3 1 24-JUL-12
4 2 24-JUL-12
5 2 24-JUL-12
Desired Result:
Final table should look similar to the one below:
MOVIE_NAME TIMES_REQUESTED DVDS_AVAILABLE
-------------------------------------------------------------------
E.T. the Extra-Terrestrial 2 3
Indiana Jones and the Kingdom 2 1
War of the Worlds 3 3
Unbreakable 3 1
I tried the following code, but did not get the result I wanted
I am assuming I need to go to dvd table first and find all dvds that match the movie_id I want and group them by movie_id. I tried the code below, but instead of returning the 4 rows I want it is returning 72.
SELECT m.movie_name, pomid.times_requested, d.dvds_available
FROM movie m,
(select *
from(
select movie_id, count(movie_id) as times_requested
from movie_queue
where status_id=0 or status_id=1
group by movie_id
) mid
where times_requested>1) pomid,
(select movie_id, count(movie_id) as dvds_available
from dvd
group by movie_id) d
WHERE m.movie_id=pomid.movie_id;
Thanks for your suggestions in how to fix this.

A join to d.movie_id is missing, that's why you get too many rows. (Quick check: how many tables do I have? How many joins do I have?)
And I'd also add an outer join to get all movies, even when there are no dvd or movie_queue entries.
SELECT m.movie_name
,NVL(pomid.times_requested,0) times_requested
,NVL(d.dvds_available,0) dvds_available
FROM movie m
,(SELECT *
FROM (SELECT movie_id
,COUNT (movie_id) AS times_requested
FROM movie_queue
WHERE status_id = 0
OR status_id = 1
GROUP BY movie_id) mid
WHERE times_requested > 1) pomid
,(SELECT movie_id
,COUNT (movie_id) AS dvds_available
FROM dvd
GROUP BY movie_id) d
WHERE m.movie_id = pomid.movie_id(+)
AND d.movie_id(+) = pomid.movie_id;
http://www.sqlfiddle.com/#!4/5437a/11

Not sure I really understand your table structure, but this might get you started:
select movie_id,
sum(case when status_id in (0,1) then 1 else 0 end) as times_requested,
count(movie_id) as dvd_available,
from movie_queue
group by movie_id;

Related

Calculating consecutive dates teradata

I am not an expert in Teradata or SQL so need some help in counting number of days a person has attended a customer
If a sales person has attended customer from 1 - 3 days consecutively this will be counted as 1 and if the person has attended 4 days then it will be counted as 2
I will add the example of data and result I want
DATA:
Sales Person Date
John 1/03/2016
John 2/03/2016
John 3/03/2016
John 4/03/2016
John 5/03/2016
David 6/03/2016
David 7/03/2016
David 8/03/2016
David 9/03/2016
David 10/03/2016
David 11/03/2016
John 12/03/2016
John 13/03/2016
John 14/03/2016
John 15/03/2016
John 16/03/2016
John 17/03/2016
John 18/03/2016
John 19/03/2016
David 20/03/2016
Sue 21/03/2016
Sue 22/03/2016
Sue 23/03/2016
Lily 24/03/2016
Lily 25/03/2016
Lily 26/03/2016
Sue 27/03/2016
David 28/03/2016
John 29/03/2016
David 30/03/2016
John 31/03/2016
RESULT WANTED:
Sales Person Groups
John 6
David 4
Sue 2
Lily 1
Excel Format Picture
Interesting problem.
Here is a solution using ordered analytical functions and nested derived tables.
The final number of points per person is in person_points. I used analytical function sum() instead of grouping because I wanted to show the intermediate steps. The rule that days in a 3-day period that overlap a previous group should not be counted was a little tricky to implement.
create table t ( person varchar(30), dt date);
insert into t values('John','2016-03-01');
insert into t values('John','2016-03-02');
insert into t values('John','2016-03-03');
insert into t values('John','2016-03-04');
insert into t values('John','2016-03-05');
insert into t values('David','2016-03-06');
insert into t values('David','2016-03-07');
insert into t values('David','2016-03-08');
insert into t values('David','2016-03-09');
insert into t values('David','2016-03-10');
insert into t values('David','2016-03-11');
insert into t values('John','2016-03-12');
insert into t values('John','2016-03-13');
insert into t values('John','2016-03-14');
insert into t values('John','2016-03-15');
insert into t values('John','2016-03-16');
insert into t values('John','2016-03-17');
insert into t values('John','2016-03-18');
insert into t values('John','2016-03-19');
insert into t values('David','2016-03-20');
insert into t values('Sue','2016-03-21');
insert into t values('Sue','2016-03-22');
insert into t values('Sue','2016-03-23');
insert into t values('Lily','2016-03-24');
insert into t values('Lily','2016-03-25');
insert into t values('Lily','2016-03-26');
insert into t values('Sue','2016-03-27');
insert into t values('David','2016-03-28');
insert into t values('John','2016-03-29');
insert into t values('David','2016-03-30');
insert into t values('John','2016-03-31');
select t_points.*
,sum(points) over(partition by person) person_points
from
(
select person, consecutive_group, min(dt) first_dt, max(dt) last_dt
, last_dt - first_dt + 1 n_days
,floor((n_days + 2) / 3)*3 + first_dt - 1 end_of_3day_period
,max(end_of_3day_period) over(partition by person order by consecutive_group rows between 1 preceding and 1 preceding) prev_end_3day_dt
,case when prev_end_3day_dt >= first_dt then prev_end_3day_dt - first_dt + 1 else 0 end overlapped_days
,n_days - overlapped_days n_days_no_overlap
, floor((n_days_no_overlap + 2)/3) points
from
(
select person,dt
,sum(begin_new_consecutive) over(partition by person order by dt rows unbounded preceding) consecutive_group
from
(
select person, dt
,max(dt) over(partition by person order by dt rows between 1 preceding and 1 preceding) prev_dt
,case when dt = prev_dt+1 then 0 else 1 end begin_new_consecutive
from t
) t_consecutive
) t_consecutive_group
group by 1,2
) t_points
order by 1,2 ;

Display records not matching in where clause

I need to display records not matching the where clause.
Example - select * from citytable where city in ('aa','bb','cc', 'dd','ee');
only aa, bb, cc are present in table, dd & ee are not present in the table. However, I still need to display dd & ee.
You are probably looking for something like this. An IN condition is the same as an inner join to a table containing the unique (distinct) values from the IN list. What you want is an outer join. You need to have a table instead of the IN list. In the solution below I show how you can create this "helper" table on the fly; there are several other methods, this just demonstrates the idea.
select deptno, ename from emp where deptno in (10, 50, 80);
DEPTNO ENAME
------ ------
10 CLARK
10 KING
10 MILLER
with h ( deptno ) as (
select 10 from dual union all
select 50 from dual union all
select 80 from dual
)
select h.deptno, e.ename
from h left outer join emp e
on h.deptno = e.deptno
;
DEPTNO ENAME
------ ------
10 CLARK
10 KING
10 MILLER
50
80
I'm not sure exactly how you want the output to look. If there is no data where city='ee', what exactly do you want to show? Something like this?
SELECT * FROM
(SELECT key AS A_key, one AS A_one, two AS A_two FROM cityTable WHERE one='aa') AS A
JOIN
(SELECT key AS E_key, one AS E_one, two AS E_two FROM cityTable WHERE one='ee') AS E
ON A_key=E_key
...etc.
Edit: or maybe this is it:
SELECT city FROM (SELECT city, count(*) AS c FROM cityTable GROUP BY city) WHERE c = 0
As i understand you said the 'dd' amd 'ee' are not present in the table but you still need it so you can achieve it using a union all. But remember that the columns of the 'dd' and 'ee' rows will always be null since there is no records present in your citytable
SELECT ct.col1 AS city, ct.col2.....<all columns of your table>
from citytable ct
where city in ('aa','bb','cc')
UNION ALL
select 'dd' as city,null ,null.....<nulls as many times as the number of columns of your table>
from citytable ct1
UNION ALL
select 'ee' as city,null ,null.....<nulls as many times as the number of columns of your table>
from citytable ct2

MS Access Query counting instances

I have a sample table with following values
SNO | Mon
-----+-------
100 | 1
101 | 1
102 | 1
100 | 2
101 | 2
102 | 2
100 | 3
101 | 3
Now I need a query to count the total sno's which are in 3 months
The result should be 2, as 100 & 101 are in mon 1,2 and 3. However, 102 is only present in mon 1,2.
Thanks,
RK
This Query in theory should work.
SELECT
tmpTbl.sNo
FROM
tmpTbl
GROUP BY
tmpTbl.sNo
HAVING
Count(tmpTbl.monNo) = (SELECT Count(*) FROM (SELECT tmpTbl.monNo FROM tmpTbl GROUP BY tmpTbl.monNo));
The result would be,
sNo
----
100
101
I have used two SubQueries to get the result. Teh both are used in the HAVING clause of the SQL. First SqubQuery (inner most). Will get the number of Unique Month's available in your table, the outer SubQuery will then Count the number of Unique months. So the Overall Query can be translated as "SELECT the serial number FROM the table HAVING the Count of Month equal to the Number of unique records in the same table".
The reason I used SbQuery instead of a number is because of the fact this will also be applicable when your month number increases. Hope this helps !
EDIT
Here is the Query for getting the count.
SELECT
Count(*) As simpleCount
FROM
(
SELECT
tmpTbl.sNo
FROM
tmpTbl
GROUP BY
tmpTbl.sNo
HAVING
Count(tmpTbl.monNo) = (SELECT Count(*) FROM (SELECT tmpTbl.monNo FROM tmpTbl GROUP BY tmpTbl.monNo))
);

in SQLite, how to do a Join avoiding specific duplicates in a column

I’m trying to extract, from a SQLite database, a set of records using a join, avoiding duplicates in one column. The problem is as follows: I have two tables, Table_A has multiple “Names” for the same row in Table_B, but I only need the first name (order by Table_A.Id). So, in the example below, I only want Alfa and Gamma in my results.
Here is an example:
Table _A
Id bId Name
----- ------ ----
1 1 Alfa
2 1 Beta
3 2 Gamma
4 2 Delta
Table_B
Id Year Title
----- ------ ------
1 1900 Doctor
2 1920 Priest
The result that I’m looking for is,
bId Name Year Title
------ ------ ----- ------
1 Alfa 1900 Doctor
2 Gamma 1920 Priest
The obvious join is as follows:
Select bID, Name, Year, Title from Table_A as a join Table_B as b on b.id=a.bid
order by bId;
Which return the following data, including beta and delta, which I don’t need.
bId Name Year Title
----- ------ ------ ------
1 Alfa 1900 Doctor
1 Beta 1900 Doctor
2 Gamma 1920 Priest
2 Delta 1920 Priest
If I change the query to
Select bID, Name, Year, Title from Table_A as a join Table_B as b on b.id=a.bid
group by bId order by bId;
Then I get something like this result that is also wrong (I get Beta & Delta instead of Alfa & Gamma)
bId Name Year Title
----- ------ ------ ------
1 Beta 1900 Doctor
2 Delta 1920 Priest
Which is not good either.
I have tried to find how to do this in SQLite, by looking at the syntax and using Google, and had been unable to find an answer. Will appreciate any help.
SELECT bID, Name, Year, Title
FROM Table_A AS A INNER JOIN Table_B AS B on B.id = A.bid
WHERE NOT EXISTS (SELECT * FROM Table_A WHERE bid = A.bid AND id < A.id)
ORDER BY bId;
This filters the results keeping only the records for which a lower id value cannot be found for the same bid value. Not highly-performant but in the case of not-huge tables it may be sufficiently quick for your needs.
Alternatively:
SELECT bID, Name, Year, Title
FROM Table_A AS A INNER JOIN Table_B AS B on B.id = A.bid
WHERE id = (SELECT MIN(id) FROM Table_A WHERE bid = A.bid)
ORDER BY bId;
If you have SQLite 3.7.11 or later, you can select which record in a group is returned by using MIN or MAX.
In this query, add MIN(A.Id) to the SELECT clause.

How to count records from multiple columns using sql and asp.net?

I have a table with 5 columns: ID, Session1, Session2, Session3, Session4. What I want to do is to display the number of same items from each column. Same item can't appear in more than one column.
ID Session1 Session2 Session3 Session4
-- -------- -------- -------- --------
1 Music Web Tech Future
2 Art Articles Search Introduction
3 Music Books Camera Phone
4 Music Glass Cup Future
5 Art Books Tech Future
6 Music Glass Cup Phone
I want to display it like this on an asp.net page.
Music: 4
Art: 2
Web: 1
Articles: 1
Books: 2
Glass: 2
Tech: 2
Search: 1
Camera: 1
Cup: 2
Future: 3
introduction: 1
Phone: 2
how would I construct a sql query and display them on asp.net?
You could simply use:
SELECT
session1,
COUNT(*)
FROM
My_Table
GROUP BY
session1
UNION ALL
SELECT
session2,
COUNT(*)
FROM
My_Table
GROUP BY
session2
...
With SQL Server you could do something like this:
SELECT Session, COUNT(*) FROM (
SELECT Session1 AS Session FROM TableName
UNION ALL
SELECT Session2 AS Session FROM TableName
UNION ALL
SELECT Session3 AS Session FROM TableName
UNION ALL
SELECT Session4 AS Session FROM TableName) T1
GROUP BY Session
It's not pretty, but it should work.
try:
Select z.Val, Count(*) ValueCount
From (Select Distinct session1 val From Table Union
Select Distinct session2 val From Table Union
Select Distinct session3 val From Table Union
Select Distinct session4 val From Table) Z
Join Table t on Z.Val In (t.Session1, t.Session2, t.Session3, t.Session4)
Group By z.Val

Resources