Error in using WITH clause and INTERSECT in SQLite - sqlite

I have two SQL queries;
First one is:
with b as (select person_id from people where name='Ward Bond' and born=1903)
select title_id from b natural join crew;
Which is producing correct results and is OK.
Another one is:
with c as (select person_id from people where name='John Wayne' and born=1907)
select title_id from c natural join crew;
Which is also totally OK and producing correct results. As soon as I try to find the intersection of these two queries using the following query:
with b as (select person_id from people where name='Ward Bond' and born=1903) select title_id from b natural join crew
intersect
with c as (select person_id from people where name='John Wayne' and born=1907) select title_id from c natural join crew;
I get the error Error: near "with": syntax error
I'm using SQLite3. Can you please help me to find the problem? The thing I'm trying to get is straightforward; I want to have the intersection of these two temporary tables.

This is the correct syntax for SQLite:
select * from (
with b as (
select person_id
from people
where name='Ward Bond' and born=1903
)
select title_id from b natural join crew
)
intersect
select * from (
with c as (
select person_id
from people
where name='John Wayne' and born=1907
)
select title_id from c natural join crew
);
Another way to get the intersected rows:
with cte(name, born) as (values ('Ward Bond', 1903), ('John Wayne', 1907))
select c.title_id
from crew c natural join people p
where (p.name, p.born) in cte
group by c.title_id
having count(distinct p.person_id) = 2;

That's how I did it using view:
create view a as select person_id from people where name='Ward Bond' and born=1903;
create view b as select person_id from people where name='John Wayne' and born=1907;
with c as
(select title_id from a natural join crew
intersect
select title_id from b natural join crew)
select primary_title from c natural join titles;

Related

Homework Question :: Tried very hard :: Need Direction

I have been stuck on this progressive question for more than 10 days now
Questions is :: Find all the actors that made more movies with Yash Chopra than any other director
Heres my attempt
SELECT pidsWhoDidMoviesWithYashChopra.pid,
pidsWhoDidMoviesWithYashChopra.moviesWithYashChopra,
pidsOfThoseWhoDidMoviesWithDirectors.moviesByAPID,
pidsWhoDidMoviesWithYashChopra.countOfMoviesWithYashChopraByAPID,
pidsOfThoseWhoDidMoviesWithDirectors.totalNumberOfMoviesByAPID
FROM
(
SELECT TRIM(M_Cast.PID) AS pid, moviesByYashChopra.mDirectorMID AS moviesWithYashChopra, COUNT(moviesByYashChopra.mDirectorMID) AS countOfMoviesWithYashChopraByAPID
FROM M_Cast
JOIN
(
SELECT TRIM(M_Director.MID) AS mDirectorMID
FROM
M_Director
WHERE TRIM(M_Director.PID) IN
(
SELECT TRIM(Person.PID) AS personPID
FROM
Person
WHERE Person.Name LIKE '%Yash Chopra%'
)
) AS moviesByYashChopra
ON TRIM(M_Cast.MID) == moviesByYashChopra.mDirectorMID
GROUP BY pid
) AS pidsWhoDidMoviesWithYashChopra
JOIN
(
SELECT TRIM(M_Cast.PID) AS pid, TRIM(M_Cast.MID) AS moviesByAPID, COUNT(TRIM(M_Cast.MID)) AS totalNumberOfMoviesByAPID
FROM M_Cast
GROUP BY pid
) AS pidsOfThoseWhoDidMoviesWithDirectors
ON pidsWhoDidMoviesWithYashChopra.pid == pidsOfThoseWhoDidMoviesWithDirectors.pid
GROUP BY pidsWhoDidMoviesWithYashChopra.pid
And here's the output it produces
And here's the schema
Now where I require help is :: Ability to go ahead from here :: As in how do i dissect this part of the question "than any other director." :: I think that's the tricky part
Any direction/hints will be helpful, Thanks...
You need to join person (for the actor's details) with m_cast, movie, m_director and person again (for the director's details) and group by actor and director to count the number of movies each actor made with each director.
Then use window functions first_value() to get the name of the director with whom the actor made the most movies and lag() to get the 2nd max number of movies (this is needed to filter out ties).
Enclose this query inside a CTE and then filter:
with cte as (
select pa.pid, pa.name, count(*) counter,
first_value(pd.name) over (partition by pa.pid, pa.name order by count(*) desc) max_dir_name,
lag(count(*)) over (partition by pa.pid, pa.name order by count(*) desc) prev_counter
from person pa
inner join m_cast c on c.pid = pa.pid
inner join movie m on m.mid = c.mid
inner join m_director d on d.mid = m.mid
inner join person pd on pd.pid = d.pid
group by pa.pid, pa.name, pd.name
)
select pid, name, counter
from cte
where max_dir_name = 'Yash Chopra' and coalesce(prev_counter, 0) < counter

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

Proc sql to Pull data from different tables recursively

I need to perform a recursive count operation on tables but here are the challenges that I am facing with.
Lets say I have tables A, B, C, D, E, F, .... Z
Here is the code snippet of what I have,
Proc sql;
create table temp as(
select count(*)
from a
inner join b on a.id = b.id
inner join c on a.id = c.id
inner join d on a.id = d.id
where <condition>
);
Once this code is complete I need to run the same query with B, C, D and E and update the result in same temp table that I am trying to create. This way I have to do for the entire table list that I have.
Is there a recursive sql to do this. I don't require a separate macro to call the query each time with different tables.
I would not do it quite this way.
proc sql;
create table temp as (
select count(case when n(a.id,b.id,c.id,d.id)=4 then 1 else 0 end) as abcd_count,
count(case when n(b.id,c.id,d.id,e.id)=4 then 1 else 0 end) as bcde_count
from a outer join b on a.id=b.id
outer join c ... etc.
;
quit;
IE, just do one join and use case when... to determine what has the counts you need. Here I use n() to identify records with all 4 ids on them.

multi table insert fecthing value from another table

I have tables - FAKE_CUST, PRE_CUST, NORMAL_CUST. Based on the constraint present in FAKE_CUST table, the value has to be brought to either PRE_CUST or NORMAL_CUST.
I am using the follwing code:
INSERT ALL
INTO PRE_CUST(CUST_ID, TOTAL_COST_TRANS) (SELECT DISTINCT CUST_ID,C FROM (
SELECT CUST_ID, SUM(COST_TRANS) OVER (PARTITION BY CUST_ID) as C FROM FAKE_CUST) WHERE C>1000)
INTO NORMAL_CUST(CUST_ID, TOTAL_COST_TRANS) (SELECT DISTINCT CUST_ID,C FROM (
SELECT CUST_ID, SUM(COST_TRANS) OVER (PARTITION BY CUST_ID) as C FROM FAKE_CUST) WHERE C<1000)
SELECT 1 FROM DUAL;
The syntax which you have used for multi-table insert is not correct to start with.
The WHEN clause, which evaluates the condition for insert, has to come before insert_intoclause.
Your query should look like this:
INSERT ALL
WHEN c > 1000 THEN
INTO pre_cust (cust_id, total_cost_trans)
WHEN c < 1000 THEN
INTO normal_cust (cust_id, total_cost_trans)
SELECT CUST_ID, SUM(COST_TRANS) OVER (PARTITION BY CUST_ID) as C
FROM FAKE_CUST

Getting two different values for same atribute from a single table in SQL

I am having three tables viz. Bids(bid_id,base_price),Customer(customer_id,name,..) and Customer_Bid(customer_id,bid_id,bidding_amount) where customer bids and his bidded amount is stored in Customer_Bid table.
I want to show the details of customer along with his bidded id and the one with highest bid for same bid id.
I have tried to get the customer details but i am not able to show his bidded amount along with the highest bidded amount whish resides in same table.
Plz any one can help me out.
Thanks.
Edit This is the query that was in the comment
select cb.bid_id, c.customer_id ,MyBid=cb.total_bidding_ammount
, HighestBid= max(cb.total_bidding_ammount)
from customer as c
,customer_bidding as cb
,bid as b
group by cb.bid_id, c.customer_id, cb.total_bidding_ammount
If you change this:
, HighestBid= max(cb.total_bidding_ammount)
to something like this:
, HighestBid =
(select max(bidding_ammount)
from customer_bidding
where bid_id = bid.bid_id)
You will on the right track.
Try this one:
SELECT cb.bid_id,
c.customer_id,
cb.total_bidding_ammount,
topbids.customer_id as topbid_customer_id,
topbid
FROM customer c
INNER JOIN customer_bidding as cb
ON c.customer_id = cb.customer_id
INNER JOIN (
SELECT cb.bid_id, c.customer_id, MAX(cb.total_bidding_ammount) as topbid
FROM customer c
INNER JOIN customer_bidding cb
ON (c.customer_id = cb.customer_id)
GROUP BY cb.bid_id
) topbids
ON cb.bid_id = topbids.bid_id
select a.*, b.bidding_amount,
e.bidding_amount as highest_bid
from customer a
inner join customer_bid b on a.customer_id = b.customer_id
inner join bids c on b.bid_id = c.bid_id
join
(select * from (
select bidding_amount,bid_id
from customer_bid
order by bidding_amount desc
) d group by d.bid_id) e on b.bid_id = e.bid_id

Resources