SQL - Finding the AVG, MIN, MAX and SUM with ID - sql

The task I have been given requires me to find the average, minimum, maximum and total cost of visits made by Tiddles the cat 'P0001' and vet Trevor McCafferty 'VO4'. This will be drawn from two tables, pet and visit.
Pet table structure:
pet_id, Name, Type, Breed, Gender, Born, owner_id, Notes
Visit table structure:
visit_id, pet_id, vet_id, Visit_Date, Basic_Cost, Symptom, Treatment
Below is the command I have created so far but I'm not sure if I'm doing this correctly which is why I need help.
SELECT Name, Type, AVG(Basic_Cost), MIN(Basic_Cost), MAX(Basic_Cost), SUM(Basic_Cost)
FROM visit, pet
WHERE pet_id = 'P0001' AND vet_id = 'V04';
Any questions just ask and any help is appreciated as I'm stumped.

SELECT FIRST(pet.Name) AS PetName,
FIRST(pet.Type) AS PetType,
AVG(Basic_Cost) AS AverageCost,
MIN(Basic_Cost) AS MinCost,
MAX(Basic_Cost) AS maxCost,
SUM(Basic_Cost) AS TotalCost
FROM visit
INNER JOIN pet ON visit.pet_id = pet.pet_id
WHERE visit.pet_id = 'P0001'
AND visit.vet_id = 'V04'

I think you are missing GROUP BY
SELECT pet.Name, pet.Type, AVG(Basic_Cost), MIN(Basic_Cost), MAX(Basic_Cost), SUM(Basic_Cost)
FROM visit, pet
where visit.pet_id = pet.pet_id
and visit.pet_id = 'P0001'
and visit.vet_id = 'V04'
GROUP BY pet.Name, pet.Type;
Also you probably have to join visit and pet tables

Related

Grouping by country and discipline in SQLServer

i've got a problem I cannot solve in SQLServer. There are 3 tables with data about the Olympics.
Table 1: Dysciplines - contains DisciplineID (int,PK) and Discipline (varchar)
Table 2: Athletes - contains AthleteID (int, FK), Athlete (varchar, PK), Nationality (varchar) and DisciplineID(int,FK)
Table3: Medals - contains AthleteID(int, PK), Year(int) and Medals(int)
I want to extract all the countries, that got more medals in their best discipline than in all the others combined. However, I am having problem with it.
Obviously I joined all the tables, but I'm not sure how do I continue. I tried:
WHERE MAX(SUM(dbo.Medals.Medals))>SUM(dbo.Medals.Medals)-MAX(SUM(dbo.Medals.Medals))
GROUP BY tab1.Dyscypline
But this is clearly wrong. I will be grateful for any help.
You would use aggregation and having. Start with the number of medals in each discipline in each country:
select a.nationality, a.disclipineid, count(*) as num_medals
from athletes a join
medals m
on a.AthleteID = m.AthleteID
group by a.nationality, a.disclipineid;
Then aggregate again:
select nationality
from (select a.nationality, a.disclipineid, count(*) as num_medals
from athletes a join
medals m
on a.AthleteID = m.AthleteID
group by a.nationality, a.disclipineid
) am
group by nationality
having max(num_medals) > sum(num_medals) * 0.5;
That is, the maximum number of medals for a discpline accounts for more than half the medals.

PostgreSQL show latest date and one value of a column from many

I have a problem with a query, that i can't figure out. Have tried for some time, but I just can't figure it out. Would be a great deal of help if you could help me. So... I have 4 tables:
cars - ID, make, model, plate_number, price, type, year, owner_ID
persons - ID, name, surname, pers_code
insurance_data - company_ID, car_ID, first_date, last_date
companies - ID, title
My query so far is..
SELECT cars.plate_number, persons.name, persons.surname, insurance_data.last_date
FROM cars,persons,insurance_data
WHERE cars.owner_ID = persons.ID AND cars.ID = insurance_data.car_ID
This outputs cars plate number, owner of the car, and the last date of the car's insurance. But the problem is that there's two cars that have two end dates of insurance, so in the output there's two entries for same car and with both insurance end dates. What i need is that there would be only one entry for each car and corresponding insurance end date should be the latest.
I know this is pretty basic, but i'm a first year student of databases, and this is one of my first assignments. Thanks in advance
(1) Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
(2) Use table aliases!
The answer to your question is DISTINCT ON:
SELECT DISTINCT ON (c.plate_number) c.plate_number, p.name, p.surname, id.last_date
FROM cars c JOIN
persons p
ON c.owner_ID = p.ID JOIN
insurance_data id
ON c.ID = id.car_ID
ORDER BY c.plate_number, id.last_date DESC;

SQL - Get consecutively minimum numbers

Title may not make sense so I will provide some context.
I have a table, call it Movies.
A movie tuple has the values: Name, Director, Genre, Year
I'm trying to create a query that allows me to return all Directors who have never released two consecutive Horror films with more than 4 years apart.
I'm not sure where I'd begin but I'm trying to start off by creating a query that given some specific year, returns the next minimum year, so that I can check if the difference between these two is less than 4, and keep doing that for all movies.
My attempt was:
SELECT D1.Director
FROM Movies D1
WHERE D1.Director NOT IN
(SELECT D2.Director FROM Director D2
WHERE D2.Director = D1.Director
AND D2.Genre = 'Horror'
AND D1.Genre = 'Horror' AND D2.Year - D1.Year > 4
OR D1.Year - D2.Year > 4)
which does not work for obvious reasons.
I've also had a few attempts using joins, and it works on films that follow a pattern such as 2000, 2003, 2006, but fail if more than 3 films.
You could try this:
Select all data, and use lag or lead to return the last or next year. After that look at the difference between the two.
WITH TempTable AS (
SELECT
Name,
Director,
Genre,
Year,
LAG(Year) OVER (PARTITION BY Name, Director, Genre ORDER BY Year ASC) AS 'PriorYear'
FROM
Movies
WHERE
Genre = 'Horror'
)
SELECT
Name,
Director
FROM
TempTable
GROUP BY
Name,
Director
HAVING
MAX(Year-PriorYear) < 2
Try this:
SELECT * FROM (
SELECT director, min(diff) as diff FROM (
SELECT m1.director, m1.year as year1, m2.year as year2, m2.year-m1.year as diff
FROM `movies` m1, movies m2
WHERE m1.director = m2.director and m1.name <> m2.name and m1.year<=m2.year
and m1.genre='horror' and m2.genre='horror'
) d1 group by director
) d2 WHERE diff>4
First, in the inner Select it will list all movie pairs of directors' horror movies with year difference calculated, then minimum of these are selected (for consecutiveness), then longer than 4 years differences are selected...

Postgresql - retrieve rows within criteria within 30 day span

I have the following tables
AdmittedPatients(pid, workerid, admitted, discharged)
Patients(pid, firstname, lastname, admitted, discharged)
DiagnosticHistory(diagnosisID, workerid, pid, timeofdiagnosis)
Diagnosis(diagnosisID, description)
Here is an SQL Fiddle: http://sqlfiddle.com/#!15/e7403
Things to note:
AdmittedPatients is a history of all admissions/discharges of patients at the hospital.
Patients contain all patients who have records at the hospital. Patients also lists who are currently staying at the hospital (i.e. discharged is NULL).
DiagnosticHistory contains all diagnosis made.
Diagnosis has the description of the diagnosis made
Here is my task: list patients who were admitted to the hospital within 30 days of their last discharge date. For each patient list their patient identification number, name, diagnosis, and admitting doctor.
This is what I've cooked up so far:
select pid, firstname, lastname, admittedpatients.workerid, patients.admitted, admittedpatients.discharged
from patients
join admittedpatients using (pid)
group by pid, firstname, lastname, patients.admitted, admittedpatients.workerid, admittedpatients.discharged
having patients.admitted <= admittedpatients.discharged;
This returns pid's from 0, 1, and 4 when it should 0, 1, 2, and 4.
Not sure why out need group by or having here... no aggregate...
SELECT A.pid, firstname, lastname, A.workerid, P.admitted, A.discharged
FROM patients P
INNER JOIN admittedpatients A
on P.pID = A.pID
WHERE date_add(a.discharged, interval 30 day)>=p.admitted
and p.admitted >=a.discharged
updated fiddle: http://sqlfiddle.com/#!2/dc33c/30/0
Didn't get into returning all your needed fields but as this gets the desired result set I imagine it's just a series of joins from here...
Updated to postgresql:
SELECT A.pid, firstname, lastname, A.workerid, P.admitted, A.discharged
FROM patients P
INNER JOIN admittedpatients A
on P.pID = A.pID
WHERE a.discharged+ interval '30 day' >=p.admitted
and p.admitted >=a.discharged
http://sqlfiddle.com/#!15/e7403/1/0
I didn't see any diagnostic info in the fiddle, so I didn't return any.
select pid
,p.lastname,p.firstname
,ad.lastname,ad.firstname
from AdmittedPatients as a
join AdmittedPatients as d using (pid)
join Patients as p using (pid)
join AdminDoctors as ad on ad.workerid=a.workerid
where d.discharged between a.admitted-30 and a.admitted
You have a rather basic WHERE clause error here:
Admitted cannot be both before discharged AND after discharged+30
Also you have an extra semicolon before your whole query is ended, probably throwing out the last line altogether.
I think you're looking for admitted=discharged

SQL Nested Query Homework

Given :
InsuranceCompanies (cid, name, phone, address)
Doctors (did, name, specialty, address, phone, age, cid)
Patients (pid, name, address, phone, age, gender, cid)
Visits (vid, did, pid, date, description)
Where:
cid - Insurance Company code
did - doctor code
pid - patient code
vid - code of visit
And a TASK : Find doctors (did, name) with number of visits (during this year) less than average number of visits to all doctors during this year.
My attempt is:
SELECT D.did, D. name
FROM Doctor D,Visit V
WHERE V.did = D.did and D.did = CV.did and CV.visits <
(SELECT AVG ( CV.visits)
FROM (SELECT V1.did AS did,COUNT(V1.vid) AS visits
FROM Visit V1
WHERE V1.date LIKE '%2012'
GROUP BY V1.did) AS CV)
A BIG THANKS TO Bridge Who shared the most beautifull and user freindly SQL commands visualator ever!
Databse Exemple : http://sqlfiddle.com/#!2/e85c7/3
Solution using views:
CREATE VIEW ThisYear AS
SELECT v.pid,v.vid,v.did
FROM Visits v
WHERE v.date LIKE '%2012';
CREATE VIEW DoctorsVisitCount AS
SELECT v.did, COUNT(v.vid) as c
FROM ThisYear v
GROUP BY v.did;
SELECT DISTINCT d.did,d.dname,dvc.c
FROM Doctors d,DoctorsVisitCount dvc
WHERE dvc.c < (SELECT AVG(dvc.c)
FROM DoctorsVisitCount dvc);