SQL query help select from multiple tables - mysql

I have no idea how to finish this query....
The question asks:
"For each person who acted in a movie in 2010, find their name
and total pay in all movies in which they have acted (i.e. including
those not in 2010)."
The table required: (where title = Movie title, and year = Movie year, and Pay = actors pay)
ActedIn (name:varchar, title:varchar, year:int, pay:real)
My query so far:
SELECT A.name, A.pay FROM ActedIn A WHERE A.year = 2010;
This returns:
+--------+--------+
| Name | Pay |
+--------+--------+
| Dino | 12.22 |
+--------+--------+
| Miro | 1238.22|
+--------+--------+
But, this only returns the pay for the money received for the specific movie made by the actor in 2010.
Now that I have the names of the actors I want to look up, I need it to find all the other movies they made (before or after 2010), and add TOTAL PAY for all the movies they were in.
I know I need to make another table to find all the movies those 2 actors acted in, and then merge the columns I think.
Any help?

You can do this with a single aggregation and having clause:
select ai.name, sum(ai.pay)
from actedin ai
group by ai.name
having sum(case when ai.year = 2010 then 1 else 0 end) > 0;
The having clause counts the number of movies that each "name" acted in in 2010. If this number is greater than 0, then the name is kept for the result set.

You can also use exists with a subquery.
select name, sum(pay)
from actedin a
where exists (select 1 from actedin b where a.name = b.name and year = 2010)
group by name

select name, sum(pay)
from actedin
where name in (select name from actedin where year = 2010)
group by name

Related

Select Min and Max value

I have a table called 'customers':
id | name | age
1 | john | 35
2 | paul | 22
3 | ana | 26
4 | mark | 19
5 | jack | 29
i want to select the name and max age, the name and min age... something like:
john 35 mark 19
is it possible?
The below query will give you the min and max on one row as requested. If there are multiple matches for min/max you will get multiple rows. Depending on the SQL engine you use, the syntax to limit to one row is different.
SELECT cMax.Name, cMax.Age, cMin.Name, cMin.Age
FROM customers cMin
JOIN customers cMax ON
cMax.Age = (SELECT MAX(Age) FROM customers)
WHERE cMin.Age = (SELECT MIN(Age) FROM customers)
There are different types of joins (e.g. INNER, OUTER, CROSS); however, for your question it doesn't much matter which you use.
Yes, you can do it,
select name, age from customers
where age in (select max(age)
from customers union select min (age)from customers)
try this
select name, age from customers where age=(select max(age) from customers) union
select name, age from customers where age=(select min(age) from customers)
If you want them on the same row:
select cmin.*, cmax.*
from (select name, age as minage
from customers
order by age asc
fetch first 1 row only
) cmin cross join
(select name, age as maxage
from customers
order by age desc
fetch first 1 row only
) cmax;
fetch first 1 row only is standard syntax for returning only the first row of the result set. Some databases have bespoke syntax, such as limit or select top (1).
Try using this query to show MAX age:-
select * from customers where age=(select max(age) from customers);
To show MIN age use the below Query:-
select * from customers where age=(select min(age) from customers);
You could use a cross join, which will put the two query ouputs next to one another. Building off Rodrigo's queries:
select
max_cust.name,
max_cust.age,
min_cust.name,
min_cust.age
from (select name, age from customers where age=(select max(age) from customers)) as max_cust
cross join (select name, age from customers where age=(select min(age) from customers)) as min_cust
It's maybe not the most performant but it gets the right shape. Be wary of cross joins when the tables don't have exactly 1 row, as it creates a cartesian product of the rows in the tables being joined.

MySQL Query to count values

I got a table on my database that contains Book ISBNs and Suppliers:
ISBN | Supplier
12345 | iSupply
12345 | disal
13333 | disal
14444 | iSupply
15555 | disal
16666 | emporio
I need to make a query that shows the count of ISBN that appears only in one supplier. In this example the query should show:
iSupply (1)
disal (2)
emporio (1)
since ISBN 12345 appears both on iSupply and disal it should not count.
Is it possible to do that ?
EDIT: I'm trying to use some of the solutions you guys posted but it keeps loading for 5-10 with no results. The database has 100-150k records, is this a problem ? Thank you for answers
SELECT x.supplier
, COUNT(*)
FROM my_table x
LEFT
JOIN my_table y
ON y.isbn = x.isbn
AND y.supplier <> x.supplier
WHERE y.isbn IS NULL
GROUP
BY x.supplier;
Group by the SUPPLIER and get the count of each group. The inner query filters out ISBN that are in multiple SUPPLIERs
select supplier, count(*)
from your_table
where isbn not in
(
select isbn
from your_table
group by isbn
having count(*) > 1
)
group by supplier
OK, I am obviously a bit late with my answer, but it works:
SELECT suppl,count(*) cnt FROM tmp
WHERE isbn IN (SELECT isbn FROM tmp GROUP BY isbn HAVING COUNT(*)=1)
GROUP BY suppl
The subquery in the where clause returns only isbns that appear uniquely, then the outer select groups together the counts for each supplier.
Yeah, I just looked up and discovered that it is almost the same anser as "juergen d"'s but it was written independently.
Or, "a variation on the theme":
SELECT suppl,count(*) cnt FROM tmp t
WHERE not exists (SELECT 1 FROM tmp WHERE isbn=t.isbn AND suppl!=t.suppl )
GROUP BY suppl
In the end it is a matter of taste. ;-)

Grouping all in one tuple in SQL

I have a table EMP with employees id and their hireyear. And I have to get the amount of hired employees in lets say the the years 2002 and 2000. The output table should als contain the amount of hired employees in the whole time.
So the last is easy. I just have to write:
SELECT COUNT(id) AS GLOBELAMOUNT FROM EMP;
But how do I count the amount of hired employees in 2002?
I could write the following:
SELECT COUNT(id) AS HIREDIN2002 FROM EMP WHERE YEAR = 2002;
But how do I combine this in one tuple with the data above?
Maybe I should group the data by Hireyear first and then count it? But can not really imagine how I count the data for several years.
Hope u guys can help me.
Cheers,
Andrej
Use conditional aggregation, e.g.:
SELECT COUNT(id) AS GLOBELAMOUNT,
COUNT(CASE WHEN YEAR=2000 THEN 1 END) AS HIREDIN2000,
COUNT(CASE WHEN YEAR=2002 THEN 1 END) AS HIREDIN2002
FROM EMP;
In Microsoft SQL Server (Transact-SQL) at least, you can use a windowed aggregate function like this:
Select Distinct
Year
,count(Id) over (Partition by Year) as CountHiredInYear
,count(Id) over () as CountTotalHires
From EMP
This gives something like:
Year | CountHiredInYear | CountTotalHires
2005 | 3 | 12
2006 | 4 | 12
2007 | 5 | 12
Another SQL Server specific approach is the With Rollup keyword.
Select Year
,count(Id) as CountHires
From Emp
Group by Year
With Rollup
This adds a summary line for each level of grouping, with the total value for that set of rows. So here, you'd get an extra row where Year was NULL, with the value 12.
You could use two (or more) inline queries:
SELECT
(SELECT COUNT(id) FROM EMP) AS GLOBELAMOUNT,
(SELECT COUNT(id) FROM EMP WHERE YEAR = 2002) AS HIREDIN2002
or a CROSS JOIN:
SELECT GLOBELAMOUNT, HIREDIN2002
FROM
(SELECT COUNT(id) AS GLOBELAMOUNT FFROM EMP) g CROSS JOIN
(SELECT COUNT(id) AS HIREDIN2002 FROM EMP WHERE YEAR = 2002) h

MS SQL double group by

I have a table 'Hobbys' with two columns. It looks like this:
NAME | HOBBY
Alice | sport
Bob | painting
... | ...
Yves | programming
Zooey | theatre
Rows could be duplicated. For example 'Bob' with hobby 'painting' can appear twice, thrice or even more times.
I want find that people, who have more than one hobby. I tried to use query like this one:
select NAME, HOBBY
from Hobbys
group by NAME, HOBBY
order by 1, 2
But I don't know how to use the query result for second grouping by NAME.
To find the users with more than one hobby, just group by the name and count the distinct hobbies;
SELECT name
FROM hobbies
GROUP BY name
HAVING COUNT(DISTINCT hobby)>1
An SQLfiddle to test with.
If you want the users and their hobbies, you can use a CTE;
WITH cte AS (
SELECT name FROM hobbies GROUP BY name HAVING COUNT(DISTINCT hobby)>1
)
SELECT * FROM hobbies JOIN cte ON hobbies.name = cte.name
Another SQLfiddle.
I want find that people, who have more than one hobby.
In my opinion the easiest is using EXISTS
SELECT NAME,HOBBY FROM dbo.Hobbys h1
WHERE EXISTS
(
SELECT 1 FROM dbo.Hobbys h2
WHERE h1.Name = h2.Name AND h1.HOBBY <> h2.HOBBY
)
Try this..
SELECT NAME,HOBBY
FROM Hobbys
GROUP BY NAME
HAVING COUNT(HOBBY) > 1

MS Access query-String aggregation

Looking for query in MS Access for below question-
Following is my data set where last row is with NULL in Value column. Also by doing Max(Value) for each Name+Office+Person+Category, I have extracted this data to avoid multiple rows with value
ID Name Office Person Category Value
1 FMR Americas Ben Global 7
1 FMR London Ben Global 5
1 FMR London Ben Overall 4.2
156 Asset London Ben Global 13
156 Asset London Ben Overall
157 WSR Paris Zen Global 2
My Expected result set is as below- I am expecting cross mark or any indicator which will show that for ID,Name,Office,person combination has value for Global/Overll categories or not in single row. I know it's somewhat of similar to "String aggregation"
ID Name Office Person Global Overall
1 FMR Americas Ben X
1 FMR London Ben X X
156 Asset London Ben X
157 WSR Paris Zen X
Appreciate your inputs..
I played around with this a little. I created two select queries Global and Overall
Global
SELECT ID, Name, Office, Person, Category AS Global
FROM [YourTable]
WHERE Category="Global" AND Value IS NOT NULL
Overall
SELECT ID, Name, Office, Person, Category AS Overall
FROM [YourTable]
WHERE Category="Overall" AND Value IS NOT NULL
Then I created a new query to join the select queries
SELECT g.ID, g.Name, g.Office, g.Person, Global, Overall
FROM Global g
LEFT JOIN Overall o ON g.ID = o.ID AND g.Name = o.Name AND g.Office = o.Office AND g.Person = o.Person
Hope this helps.
First, get a list of unique id/name/office combinations:
SELECT DISTINCT ID, Name, Office, Person
FROM TableName
Next, create subqueries for each category:
For Global:
SELECT ID, Name, Office, Person
FROM TableName
WHERE Category="Global"
For Overall:
SELECT ID, Name, Office, Person
FROM TableName
WHERE Category="Overall"
Finally, left join the subqueries to the main query, and use an expression to show the X:
SELECT DISTINCT ID, Name, Office, Person
Iif(Global.ID Is Not Null, "X") AS IsGlobal,
Iif(Overall.ID Is Not Null, "X") AS IsOverall
FROM (TableName
LEFT JOIN (
SELECT ID, Name, Office, Person
FROM TableName
WHERE Category="Global"
) AS Global
ON TableName.ID=Global.ID
AND TableName.Name=Global.Name
AND TableName.Office=Global.Office
AND TableName.Person=Global.Person)
LEFT JOIN (
SELECT ID, Name, Office, Person
FROM TableName
WHERE Category="Overall"
) AS Overall
ON TableName.ID=Overall.ID
AND TableName.Name=Overall.Name
AND TableName.Office=Overall.Office
AND TableName.Person=Overall.Person
It may be easier for you to save the subqueries as Access queries and reference the saved queries by name, instead of including the whole subquery in this query.