how to display all columns of table - sql

i am working on a store producer for a filter. i have many types of checks in my sp just like
if(#cityId!=0 and #sourceLatitude!=0 and #sourceLongitude!=0
and #KM!=0 and #food='' and #price='' and #sort='')
but i show just one table against all checks but i am also using group and AVG().
my question is, is there any way to display all fields without writing in group by.
my code
SELECT
--cast(AVG(rr.Rates ) as decimal(10,5)) Rating,
round(AVG(rr.Rates ),2) Rating,
[dbo].[Fun_distanceCalculate](r.Latitude,r.Longitude,#sourceLatitude,#sourceLongitude) AS Distance,
[dbo].[Fun_calculate_delivery_fee](r.Latitude,r.Longitude,#sourceLatitude,#sourceLongitude) AS DeliveryCharges,
r.Id,
r.IsActive,
r.CreatedDate,
Name,
TagLine,
ApproximateCostPerPerson,
FullAddress2,
FullAddress,
Tags,
IsRecommend,
Longitude,
DeliveryTime,
IsOnline,
Logo,
ImageUrl,
Latitude,
ProductDiscount,
TagLine,
IsApproved,
Salt,
Email,
PhoneNumber,
CityId,
CountryId
FROM [dbo].[Restaurants] r left join [dbo].[RestaurantReviews] rr
on r.Id=rr.RestaurantId
WHERE r.IsActive = 1 and r.IsApproved=1 and ((r.CityId=#cityId) OR #KM > [dbo].[Fun_distanceCalculate](r.Latitude,r.Longitude,#sourceLatitude,#sourceLongitude))
--ORDER BY Id DESC
--OFFSET #PageNumber ROWS
--FETCH NEXT #pageSize ROWS ONLY
group by r.Id,Name,
r.IsActive,
TagLine,
ApproximateCostPerPerson,
FullAddress2,
FullAddress,
IsOnline,
Tags,
Logo,
IsRecommend,
Longitude,
DeliveryTime,
ImageUrl,
Latitude,
ProductDiscount,
TagLine,
IsApproved,
Salt,
Email,
PhoneNumber,
CityId,
r.CreatedDate,
CountryId

You can move the aggregation to a CTE, then join the CTE to the main query.
WITH AvgRates
AS
(
r.Id
round(AVG(rr.Rates ),2) AS Rating,
FROM [dbo].[Restaurants] r left join [dbo].[RestaurantReviews] rr on r.Id=rr.RestaurantId
--can use the WHERE filtering here or in the final select
GROUP BY r.Id
)
SELECT
av.Rating,
--rest of your query
FROM [dbo].[Restaurants] r left join [dbo].[RestaurantReviews] rr on r.Id=rr.RestaurantId
INNER JOIN AvgRates av ON r.Id = av.Id
--rest of your WHERE filtering etc.

Related

counting in three joined table

I have three tables. The first one is PrivteOwner and has 5 columns (ownerno, fname, lname, address, telno), the second one is PropertyForRent that has 10 columns (propertyno, street, city, postcode, type, rooms, rent, ownerno, staffno, branchno) and the third one is Viewing with 4 columns (clientno, propertyno, viewdate, comment).
I want to find the owner who has the most properties without a viewing. My code is as below:
SELECT
CONCAT (A.fname, ' ', A.lname) AS OwnerName,
A.ownerno, B.propertyno, B.ownerno
FROM
PrivateOwner AS A
INNER JOIN
PropertyforRent AS B ON A.ownerno = B.ownerno
LEFT JOIN
viewing AS C
SELECT
ownerno, COUNT(ownerno), viewdate
FROM
Max_Property
GROUP BY ownerno
ORDER BY COUNT(ownerno) DESC
WHERE
ROWNUM = 1 and viewdate IS NULL;
Does this code work correctly? If yes how we can write it efficiently?
It's very difficult to answer question if you don't provide data definition, data or your expected result.
Anyway, from your description I think this might get you your desired result.
SELECT
TOP 1
PrivteOwner.ownerno,
PrivteOwner.fname,
PrivteOwner.lname,
COUNT(ViewNumber) AS PropertyNumber
FROM
(
SELECT
PropertyForRent.propertyno AS propertyno
, COUNT(Viewing.propertyno) AS ViewNumber
FROM PropertyForRent
LEFT JOIN Viewing ON Viewing.propertyno = PropertyForRent.propertyno
GROUP BY PropertyForRent.propertyno
) AS NoView
JOIN PropertyForRent ON PropertyForRent.propertyno = NoView.propertyno
JOIN PrivteOwner ON PrivteOwner.ownerno = PropertyForRent.ownerno
WHERE ViewNumber = 0
GROUP BY PrivteOwner.ownerno,
PrivteOwner.fname,
PrivteOwner.lname
ORDER BY PropertyNumber DESC

Oracle sql - referencing tables

My school task was to get names from my movie database actors which play in movies with highest ratings
I made it this way and it works :
select name,surname
from actor
where ACTORID in(
select actorid
from actor_movie
where MOVIEID in (
select movieid
from movie
where RATINGID in (
select ratingid
from rating
where PERCENT_CSFD = (
select max(percent_csfd)
from rating
)
)
)
);
the output is :
Gary Oldman
Sigourney Weaver
...but I'd like to also add to this select mentioned movie and its rating. It accessible in inner selects but I don't know how to join it with outer select in which i can work just with rows found in Actor Table.
Thank you for your answers.
You just need to join the tables properly. Afterwards you can simply add the columns you´d like to select. The final select could be looking like this.
select ac.name, ac.surname, -- go on selecting from the different tables
from actor ac
inner join actor_movie amo
on amo.actorid = ac.actorid
inner join movie mo
on amo.movieid = mo.movieid
inner join rating ra
on ra.ratingid = mo.ratingid
where ra.PERCENT_CSFD =
(select max(percent_csfd)
from rating)
A way to get your result with a slightly different method could be something like:
select *
from
(
select name, surname, percent_csfd, row_number() over ( order by percent_csfd desc) as rank
from actor
inner join actor_movie
using (actorId)
inner join movie
using (movieId)
inner join rating
using(ratingId)
(
where rank = 1
This uses row_number to evaluate the "rank" of the movie(s) and then filter for the movie(s) with the highest rating.

How to find the following SQL query?

there is a table in SQL database, called Players:
Players (ID, name, age, gender, score)
where ID is the primary key.
Now I want to write a query to find the following results:
For each age, find the name and age of the player(s) with the highest score among all players of this age.
I wrote the following query:
SELECT P.name, P.age
FROM Players P
WHERE P.score = (SELECT MAX(P2.score) FROM Players P2)
GROUP BY P.age, P.name
ORDER BY S.age
However, the result of the above query is a list of players with the highest score among ALL players across all ages, not for EACH age.
Then I changed my query to the following:
SELECT P.name, P.age, MAX(P.score)
FROM Players P
GROUP BY P.age, P.name
ORDER BY P.age
However, the second query I wrote gives a list of players with each age, but for each age, there are not only the players with the highest score, but also other players with lower scores within this age group.
How should I fix my logic/query code?
Thank you!
You can use rank to do this.
select name, age
from (
SELECT *,
rank() over(partition by age order by score desc) rnk
FROM Players) t
where rnk = 1
Your original query is quite close. You just need to change the subquery to be a correlated subquery and remove the GROUP BY clause:
SELECT P.name, P.age
FROM Players P
WHERE P.score = (SELECT MAX(P2.score) FROM Players P2 WHERE p2.age = p.age)
ORDER BY P.age;
The analytic ranking functions are another very viable method for processing this question. Both methods can take advantage of an index on Players(age, score). This also wants an index on Players(score). With that index, this should have better performance on large data sets.
You can try it also.
SELECT p.name, p.age, p.score
FROM players p
INNER JOIN
(SELECT `age`, MAX(`score`) AS Maxscore
FROM players
GROUP BY `age`) pp
ON p.`age` = pp.`age`
AND p.`score` = pp.Maxscore;
Try it this will resolve your issue :
select p1.name,p1.age,p1.score from players p1 where p1.score =
(SELECT max(score) from players where age = p1.age) group by p1.age;
If you will required all records having same maximum score :
Then you will use this. I have tested both the query on my localhost.
SELECT p1.name,p1.age,p1.score FROM players p1
WHERE p1.score IN (SELECT MAX(score) FROM players GROUP BY age)

SQL select, 3 tables

How can I use select if I have 3 tables?
Tables:
school_subject(ID_of_subject, workplace, name)
student(ID_of_student, firstName, surname, adress)
writing(ID_of_action, ID_of_sbuject, ID_of_student)
I want to write the student's name and surname (alphabetically) who have workplace=home.
Is this possible? And how to alphabetize?
SELECT s.firstName, s.surname
FROM student S, school_subject P, writing Z
WHERE P.workplace = 'home'
AND P.ID_of_subject = Z.ID_of_subject
AND Z.ID_of_student = s.ID_of_student;
SELECT s.firstName, s.surname
FROM student S INNER JOIN writing Z
ON Z.ID_of_student = s.ID_of_student
INNER JOIN school_subject P
ON P.ID_of_subject = Z.ID_of_subject
WHERE P.workplace = 'home'
ORDER BY S.firstName, S.surname // Sort the list
To order alphabetically the result it is possible to use ORDER BY keyword. So your query becomes:
SELECT DISTINCT S.firstName, S.surname
FROM student S, school_subject P, writing Z
WHERE P.workplace = 'home' AND
P.ID_of_subject = Z.ID_of_subject AND
Z.ID_of_student = S.ID_of_student
ORDER BY S.surname, S.firstName
The DISTINCT keyword is necessary, because in writing table there are eventually more tuples given keys ID_of_subject and ID_of_student.
So this is necessary to avoid repeating firstName and surname many times.
Note that each student is identified by ID_of_student, not by firstName and surname, so as #danjok said use DISTINCT if you only want the name and surname.
If you want to select all students that satisfy your requirement (even if two or more students have the same firstName and surname), you should including ID_of_student on SELECT clause:
SELECT S.ID_of_student, S.firstName, S.surname
FROM student S
INNER JOIN writing W ON W.ID_of_student = S.ID_of_student
INNER JOIN school_subject P ON P.ID_of_subject = W.ID_of_subject
WHERE P.workplace = 'home'
ORDER BY S.firstName asc, S.surname asc

Adding 0 or null to missing fields

I have the following tables:
student(sid, sname)
teacher(tid, tname)
enrollment(sid, cid, tid)
course(cid, course)
rank(sid, tid, grade, date, valid)
I need to calculate the average grade of all the teachers (data is in rank table), when only the grade from the most recent date counts (and if it's invalid - ignore it).
I wrote the following query, and it's working nice. The problem is that I also need the average for ALL the teachers, including those who were not ranked yet/their rank is invalid (their average grade will be 0 in that case, and I'll have to count their students like I did for the others).
I think it's something with LEFT OUTER JOIN, but all the examples I see online have only two tables in FROM, and I can't figure out the right syntax in my case.
SELECT teacher.tid,
tname,
AVG(grade) AS avgGrade,
COUNT(DISTINCT enrollment.sid) AS studCount
FROM rank,
teacher,
enrollment,
( SELECT rank.sid, rank.tid, MAX(date) AS maxDate
FROM rank
GROUP BY sid, tid
) lastGrades
WHERE teacher.tid=enrollment.tid
AND rank.tid=teacher.tid
AND rank.tid=lastGrades.tid
AND rank.sid=lastGrades.sid
AND rank.date=lastGrades.maxDate
AND valid = TRUE
GROUP BY teacher.tid, tname
You could use a subquer to look up the latest rank per (teacher, student) combination. Use a left join to count enrollments that have not been ranked:
select t.tid
, t.tname
, avg(r.grade) as AverageRank
, count(distinct e.sid) as StudentCount
from teacher t
join enrollment e
on t.tid = e.tid
left join
rank r
on r.tid = t.tid
and r.sid = e.sid
and r.valid = true
and r.date =
(
select max(date)
from rank r2
where r2.sid = r.sid
and r2.tid = r.tid
and r2.valid = true
)
group by
t.tid
, t.tname
Example without data at SQL Fiddle.
The table design is kind of strange. You'd expect a student to enroll in a course, not in a teacher!