Referencing a past query in a loop SQLite - sqlite

I want to intersect two or more results from a query from a for loop
My code takes in strings from the command line and checks the database for movies with matching actors
movie database
id | name
actor database
id | name
acting
movie_id | actor_id
i.e.
inp = sys.argv[1]
query =
'''
SELECT m.name
FROM movie m
JOIN acting ag on m.id = ag.movie_id
JOIN actor a on a.id = ag.actor_id
WHERE a.name = ?
'''
cur.execute(query, (inp,))
for tup in cur.fetchall:
print(tup)
This program would get all the movies with actor called David
./program "David'
The Secret Life of Pets
The Big Short
Concussion
A Most Violent Year
Baggage Claim
Skyfall
Drive
Albert Nobbs
The Book of Eli
Shine a Light
The Bourne Ultimatum
The Simpsons Movie
I want to extend my program to take in multiple arguments, taking in multiple names of actors, where the actors act in the same movie.
Possible code?
for index in range(len(sys.argv - 1)):
# insert code here
I think I should use an intersection of the outputs of the queries, but I don't know how to do that.
This is the output of movies that both Albert and David
./program "Albert" "David"
A Most Violent Year
Baggage Claim
The Simpsons Movie

You can use aggregation to construct a query that returns the common movies of all actors that you pass as arguments:
query = """
SELECT m.name
FROM movie m
JOIN acting ag on m.id = ag.movie_id
JOIN actor a on a.id = ag.actor_id
WHERE ',' || ? || ',' LIKE '%,' || a.name || ',%'
GROUP BY m.id, m.name
HAVING COUNT(*) = ?
"""
cur = con.cursor()
cur.execute(query, (','.join(sys.argv[1:]), len(sys.argv)-1))
for tup in cur.fetchall():
print(tup[0])

Related

DISTINCT key word issues in SQLite

Trying to run a query that should bring back all mechanics and a sum of all their commissions from another table but only getting one mechanics name and a sum of all commissions. Tried writing the query in different ways but getting the same result.
The Query:
SELECT DISTINCT m.mechID, fname || ' ' || lname AS 'Full Name', SUM(commission) AS 'Total Commissions Per Mechanic'
FROM
mechanics AS m
INNER JOIN mech_commissions AS mc on m.mechID = mc.mechID
ORDER BY "Full Name";
The output:
I think you want an aggregation query here:
SELECT m.mechID, m.fname || ' ' || m.lname AS `Full Name`,
SUM(mc.commission) AS `Total Commissions Per Mechanic`
FROM mechanics AS m
INNER JOIN mech_commissions AS mc ON m.mechID = mc.mechID
GROUP BY 1, 2
ORDER BY `Full Name`;

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

Why would oracle subquery with AND & OR return returning wrogn results set

I have two subqueries. as shown below. the first query works fine but the second query which is basically the first query that I modified to use AND & OR, doesn't work in the sense that it doesn't return ID as expected. any suggestions on what is happening here?
1. (SELECT * FROM (SELECT EMPID FROM EVENT_F
INNER JOIN WCINFORMATION_D
ON EVENT_F.JOB_INFO_ROW_WID= WCINFORMATION_D.ROW_WID
INNER JOIN WCANDIDATE_D ON WCCANDIDATE_D.ROW_WID = VENT_F.CANDIDATE_ROW_WID
WHERE STEP_NAME = 'Offer'
AND WCINFORMATION_D.JOB_FAMILY_NAME IN ('MDP','ELP','Emerging Leader Program','Other')
AND TITLE NOT IN ('Student Ambassador Program for Eligible Summer Interns','Student Ambassador')
AND PI_CANDIDATE_NUM = OUTERAPP.PI_CANDIDATE_NUM
--limit 1
ORDER BY CREATION_DT ASC
) T1 WHERE ROWNUM=1) AS A_ID,
2.(SELECT * FROM (SELECT EMPID FROM EVENT_F
INNER JOIN WCINFORMATION_D
ON EVENT_F.JOB_INFO_ROW_WID= WCINFORMATION_D.ROW_WID
INNER JOIN WCANDIDATE_D ON WCCANDIDATE_D.ROW_WID = VENT_F.CANDIDATE_ROW_WID
WHERE STEP_NAME = 'Offer'
AND WCINFORMATION_D.JOB_FAMILY_NAME IN ('MDP','ELP','Emerging Leader Program','Other') or WCINFORMATION_D.JOB_FAMILY_NAME NOT IN ('MDP','ELP','Emerging Leader Program','Other')
AND TITLE NOT IN ('Student Ambassador Program for Eligible Summer Interns','Student Ambassador')
AND PI_CANDIDATE_NUM = OUTERAPP.PI_CANDIDATE_NUM
--limit 1
ORDER BY CREATION_DT ASC
) T1 WHERE ROWNUM=1) AS A_ID,
If you're wanting to get the count of people in one set of job families, plus a count of people in another set, you need to use a conditional count, e.g. something along the lines of:
SELECT COUNT(CASE WHEN wid.job_family_name IN ('MDP', 'ELP', 'Emerging Leader Program', 'Other') THEN 1 END) job_family_grp1,
COUNT(CASE WHEN wid.job_family_name IS NULL OR wid.job_family_name NOT IN ('MDP', 'ELP', 'Emerging Leader Program', 'Other') THEN 1 END) job_family_grp2
FROM event_f ef
INNER JOIN wcinformation_d wid
ON ef.job_info_row_wid = wid.row_wid
INNER JOIN wcandidate_d wcd
ON wcd.row_wid = ef.candidate_row_wid
WHERE step_name = 'Offer' -- alias this column name
AND title NOT IN ('Student Ambassador Program for Eligible Summer Interns', 'Student Ambassador') -- alias this column name;
You will most likely need to amend this to work for your particular case (it'll have to go as a join into your main query, given there are two columns being selected) since you didn't provide enough information in your question to give us the wider context.

Counting 2 Columns from Separate Tables Between 2 Dates

I have a query that Counts 2 columns from 2 separate tables using subqueries, which works. Now I have to implement into this query the ability to filter out these results based on the Date of a Call Record. I will post the query in which I am working with:
SELECT (m.FirstName || " " || m.LastName) AS Members,
(
SELECT count(CallToLineOfficers.MemberID)
FROM CallToLineOfficers
WHERE CallToLineOfficers.MemberID = m.MemberID
)
+ (
SELECT count(CallToMembers.MemberID)
FROM CallToMembers
WHERE CallToMembers.MemberID = m.MemberID
) AS Tally
FROM Members AS m, Call, CallToMembers, CallToLineOfficers
Join Call on CallToMembers.CallID = Call.CallID
and CallToLineOfficers.CallID = Call.CallI
WHERE m.FirstName <> 'None'
-- and Call.Date between '2017-03-21' and '2017-03-22'
GROUP BY m.MemberID
ORDER BY m.LastName ASC;
Ok, so table Call stores the Date and its PK is CallID. Both CallToLineOfficers and CallToMembers are Bridge Tables that also contain only CallID and MemberID. With the current query, where the Date is commented out, that Date range should only return all names, but a count of 1 should appear under 1 person's name.
I have tried joining Call.CallID with both Bridge Tables' CallIDs without any luck, though I think this is the right way to do it. Could someone help point me in the right direction? I am lost. (I tried explaining this the best I could, so if you need more info, let me know.)
UPDATED: Here is a screenshot of what I am getting:
Based on the provided date in the sample, the new results, with the Date, should be:
Bob Clark - 1
Rob Catalano - 1
Matt Butler - 1
Danielle Davidson - 1
Jerry Chuska - 1
Tom Cramer - 1
Everyone else should be 0.
At the moment, the subqueries filter only on the member ID. So for any member ID in the outer query, they return the full count.
To reduce the count, you have to filter in the subqueries:
SELECT (FirstName || " " || LastName) AS Members,
(
SELECT count(*)
FROM CallToLineOfficers
JOIN Call USING (CallID)
WHERE MemberID = m.MemberID
AND Date BETWEEN '2017-03-21' AND '2017-03-22'
)
+ (
SELECT count(*)
FROM CallToMembers
JOIN Call USING (CallID)
WHERE MemberID = m.MemberID
AND Date BETWEEN '2017-03-21' AND '2017-03-22'
) AS Tally
FROM Members AS m
WHERE FirstName <> 'None'
ORDER BY LastName ASC;

SQLite Join Causing Duplicate Data After First Correct Record

I am having an issue where after the first record in a Select statement the data in a certain column is being duplicated within the Select statement. I will provide the statement in which I am working with:
SELECT Call.CallID AS [Call #],
(Members.FirstName || ' ' || Members.LastName) AS OIC,
Alarm.AlarmID,
Alarm.AlarmDesc AS Alarm,
--Group_Concat(m2.FirstName || ' ' || m2.LastName) AS [Line Officers],
Group_Concat(m1.FirstName || ' ' || m1.LastName) AS Members
FROM Call
LEFT JOIN
Members ON Call.OIC = Members.MemberID
LEFT JOIN
Alarm ON Call.AlarmID = Alarm.AlarmID
LEFT JOIN
CallToMembers ON Call.CallID = CallToMembers.CallID
--LEFT JOIN
--CallToLineOfficers on Call.CallID = CallToLineOfficers.CallID
LEFT JOIN
Members AS m1 ON CallToMembers.MemberID = m1.MemberID
--LEFT JOIN
--Members as m2 on CallToLineOfficers.MemberID = m2.MemberID
GROUP BY Call.CallID;
Ok, so this statement returns everything that I need and is working perfectly. However, whenever I uncomment the lines that are commented out so that I can obtain "Line Officers" from the Bridge Table "CallToLineOfficers", data begins to duplicate from within the columns like so:
Incorrect Complete Select Statement
- Nothing commented out.
Correct Line Officers
- If I comment Joins for CallToMembers.
Correct Members
- If I comment Joins for CallToLineOfficers.
As you can see that once I introduce both "Members" and "Line Officers", things go wrong.
When you join the calls with the line officers, you get an intermediate result like this:
Call # Line Officers
------ -------------
54 Bob Clark
54 Rob Catalano
When you then join with the members, the database matches the call number again, so for each row in the intermediate result, you get all combinations with the members:
Call # Line Officers Members
------ ------------- -----------
54 Bob Clark Matt Butler
54 Rob Catalano Matt Butler
54 Bob Clark Tom Cramer
54 Rob Catalano Tom Cramer
...
So you cannot use joins when you have multiple independent tables with 1:N relationships.
You don't actually want to have multiple line officer/member rows in the result anyway, so you can just use a subquery to aggregate those values:
SELECT CallID,
(SELECT group_concat(FirstName || ' ' || LastName)
FROM CallToLineOfficers
JOIN Members USING (MemberID)
WHERE CallID = Call.CallID
) AS "Line Officers",
(SELECT group_concat(FirstName || ' ' || LastName)
FROM CallToMembers
JOIN Members USING (MemberID)
WHERE CallID = Call.CallID
) AS Members
FROM Call;

Resources