SQL query creation - mysql

I have to do a query without using views that displays the automobile brand that has the maximum number of cars that have a single owner.
that's the table that I have
CAR(idcar, brand, name, year_p)
OWNER(idowner,name, b_date)
PROPERTY(idcar,idowner,date_b, date_s)
That's what I was writing..
SELECT Car.brand, COUNT(PROPERTY.idowner) as con
FROM PROPERTY JOIN CAR ON Car.idcar=Property.idcar
GROUP BY Car.brand
ORDER BY con ASC
LIMIT 1;
It's ok? what I can do to improve it?
That's how it should work
CAR
-----------------
1|FIAT|test1|2000
2|Alfa|test2|2011
3|FIAT|test3|2001
4|Alfa|test4|2006
5|Alfa|test5|2004
OWNER
-----------
1|John|1990
2|Jack|1980
3|Sam |1991
4|Rick|1980
5|Cris|1993
6|Holm|1992
PROPERTY
-------------
1|1|2000|2000
2|1|2001|2003
3|2|2000|2004
1|3|2002|2005
4|4|2004|2006
5|6|2003|2008
2|5|2001|2009
So the query should return Alfa because I've 3 people that have only one car and those 3 people have one alfa ( so 3 alfa). It can't be FIAT because I only have 2 people with only one car that is a FIAT(so 2 FIAT). The OWNER n1 is excluded because he has 2 car

I think you were on the right path with your query, it's only need a little modification...
First if you want to select brand with most owner than you should order them in descending order so the max will be at the top... And second you need to add WHERE clause which will exclude all owner that have more then one car...
It should look like this:
SELECT c.brand, COUNT(p.idowner) as con
FROM PROPERTY p
JOIN CAR c
ON c.idcar=p.idcar
WHERE p.idowner NOT IN (SELECT idowner
FROM (SELECT idowner, COUNT(idowner) as c
FROM PROPERTY
GROUP BY idowner) x
WHERE c > 1)
GROUP BY c.brand
ORDER BY con DESC
LIMIT 1;
Here is the SQL Fiddle to take a look how it's work...
GL!

This is too long for a comment.
Your query is not correct. It returns the brands that have the most properties for its cars. That may or may not have to do with the number of owners. I'm sure there's a relationship of some sort ("no properties" --> "no owners" and vice versa).
In any case, I don't know what you mean by "the maximum number of cars that have a single owner". You should edit your question with sample data and desired results. A SQL Fiddle would also be helpful.

--CTE to Get single owner
WITH CTEsingleowner(ct, idowner)
AS (SELECT Count(1) AS ct,
idowner
FROM property WITH(nolock)
GROUP BY idowner
HAVING Count(1) = 1)
-- Select brand with maximum number of single owner
-- with ties is used to resolve confilict more than one record set returned
SELECT TOP (1) WITH ties Count(1) AS cnt,
brand
FROM CTEsingleowner ct
JOIN property p WITH(nolock)
ON p.idowner = ct.idowner
JOIN car c WITH(nolock)
ON ( c.idcar = p.idcar )
GROUP BY brand
ORDER BY cnt DESC ;
--CTE to Get single owner
WITH CTEsingleowner(ct, idowner)
AS (SELECT Count(1) AS ct,idowner
FROM property WITH(nolock)
GROUP BY idowner
HAVING Count(1) = 1)
-- Select brand with maximum number of single owner
-- with ties is used to resolve conflict more than one rows returned
SELECT TOP (1) WITH ties Count(1) AS cnt, brand
FROM CTEsingleowner ct
JOIN property p WITH(nolock)
ON p.idowner = ct.idowner
JOIN car c WITH(nolock)
ON ( c.idcar = p.idcar )
GROUP BY brand
ORDER BY cnt DESC ;

Related

SQL: how to select max value from one table and other data from another table

I want to select naziv and slika from the first table (predmet table), and iznos_ponude from the second table (ponuda table).
It's an auction system. The first table represents the objects on auction (BMW, Mercedes etc.), the second table represents the id (predmet_id is the foreign key) of the object and the bid for that object.
I need to display EVERY object with the HIGHEST bid for it.
Example: BMW - IMAGE URL - 17000
This will help you understand better:
naziv = name
slika = image
iznos_ponude = bid
Another way of doing this in SQL Server using row_number() like following.
SELECT *
FROM (SELECT t1.naziv,
t1.slika,
T2.iznos_ponude,
Row_number()
OVER(
partition BY T2.predmet_id
ORDER BY iznos_ponude DESC) rn
FROM predmet T1
INNER JOIN ponuda T2
ON T1.predmet_id = T2.predmet_id)t
WHERE rn = 1
Same thing can also be achieved using subquery like following.
SELECT t1.naziv,
t1.slika,
(SELECT Max(iznos_ponude)
FROM ponuda
WHERE predmet_id = T1.predmet_id) iznos_ponude
FROM predmet T1
If you want to include objects with no bids, use left join and group by:
select p.naziv, p.slika, max(po.iznos_ponude)
from predmet p left join
ponude po
on po.predmet_id = p.predmet_id
group by p.naziv, p.slika;

Using select from another select in MySQL

I have the following query where I will have finally a 205 patient IDs to work with:
select
patient_id
FROM
visit
WHERE
month(visit.date_of_visit)=3
AND
year(visit.date_of_visit)=2018
AND
visit.visit_status='Active'
GROUP BY patient_id
I want to get all the 205 IDs and run them into other query to see how many diseases we have as cardio-vascular and then as respiratory disease.
My database structure is as the following:
What I want is to get for each patient id, what they are diagnosed at ONLY their first visit to the hospital (so here we will work with min(visit.date_of_visit))
The desired result for `diagnosis_name LIKE '%Cardio%':
E.g>:
Patients: 150 (Or something)
And the query is changed to get the respiratory info.
I tried the following for the Cardio diseases where I use select from select:
SELECT count(*)
FROM
(
select
min(visit.date_of_visit), visit_id, patient_id, count(*) as patientId
FROM
visit
WHERE
month(visit.date_of_visit)=3
AND
year(visit.date_of_visit)=2018
AND
visit.visit_status='Active'
GROUP BY patient_id
) as vid
LEFT JOIN
consultation ON consultation.visit_id=vid.visit_id
LEFT JOIN
diagnosis ON diagnosis.diagnosis_id=consultation.diagnosis_id
WHERE diagnosis.diagnosis_name LIKE '%Cardio%'
The result was: 5 which is a wrong number.
This can be done easily with PHP and MYSQL together but this will exhaust the server by repeating the same query for 205 times and increment a counter. So the desired result should be only done with MySQL.
Data example:
Visit Table
visit_id= 1; date_of_visit=2018-03-03; visit_reason=Active; ...;
patient_id=1234;
visit_id= 2; date_of_visit=2018-03-04; visit_reason=Active; ...;
patient_id=1239;
visit_id= 3; date_of_visit=2018-03-07; visit_reason=Active; ...;
patient_id=1234;
Consultation Table
consultation_id=1; ...; diagnosis_id=12; visit_id=1;...;
consultation_id=2; ...; diagnosis_id=12; visit_id=2;...;
Diagnosis Table
diagnosis_id=12; diagnosis_name: hypertension (cardio disease);
diagnosis_id=13; diagnosis_name: renal disease
By running the query to see patients who came to hospital and that they were diagnosed as having cardio disease in their initial first visit, the result should be in the example as 2 as you can see from the example where patient_id=1234 had 2 visits but I need to know what he had in his first one.
You can use window functions in MySQL 8+. But in older versions you need to calculate the value some other way.
The question for you is what you are counting:
SELECT COUNT(*) as num_diagnoses, COUNT(DISTINCT patient_id) as num_patients
FROM visit v JOIN
(SELECT patient_id,
MIN(v.date_of_visit) as min_dov
FROM visit v
WHERE v.date_of_visit >= '2018-03-01' AND
v.date_of_visit < '2018-04-01' AND
v.visit_status = 'Active'
) vf
ON v.patient_id = vf.patient_id AND v.date_of_visit = vf.min_dov JOIN
consultation c
ON c.visit_id = v.visit_id JOIN
diagnosis d
ON d.diagnosis_id = c.diagnosis_id
WHERE d.diagnosis_name LIKE '%Cardio%';
When working with dates, it is best to compare column values directly to dates, rather than dissecting them.
BRO, it works fine. Test it now on the live scenario.
SELECT count(*)
FROM
(
select
min(visit.date_of_visit) first_date, patient_id, count(*) as patientId
FROM
visit
WHERE
month(visit.date_of_visit)=3
AND
year(visit.date_of_visit)=2018
AND
visit.visit_status='Active'
GROUP BY patient_id
) as vid
INNER JOIN visit b ON
B.patient_id = vid.patient_id AND
B.date_of_visit = vid.first_date and
month(B.date_of_visit)=3 AND
year(B.date_of_visit)=2018 AND
B.visit_reason='Active'
INNER JOIN consultation ON
consultation.visit_id = B.visit_id
INNER JOIN diagnosis ON
diagnosis.diagnosis_id = consultation.diagnosis_id AND
diagnosis.diagnosis_name LIKE '%Cardio%'

The query is not giving a desired output which I want

Query with OR which outputs wrong
SELECT DISTINCT
sm___employees.id,
sm___employees.employee_code,
sm___employees.leaving_date,
sm___employees.name_of_employee,
sm___employees.position,
sm___employees.rating,
sm___employees.entry_date
FROM
sm___employees
JOIN
sm___employee_skills
ON
sm___employees.id=sm___employee_skills.employee_id
WHERE
((sm___employee_skills.skill_id=1 AND sm___employee_skills.ans LIKE '%MBA%')
**OR**
(sm___employee_skills.skill_id=5 AND sm___employee_skills.ans IN (3)))
AND
sm___employees.rating IN (1)
ORDER BY
sm___employee_skills.date DESC
But I want it by And
SELECT DISTINCT
sm___employees.id,
sm___employees.employee_code,
sm___employees.leaving_date,
sm___employees.name_of_employee,
sm___employees.position,
sm___employees.rating,
sm___employees.entry_date
FROM
sm___employees
JOIN
sm___employee_skills
ON
sm___employees.id=sm___employee_skills.employee_id
WHERE
((sm___employee_skills.skill_id=1 AND sm___employee_skills.ans LIKE '%MBA%')
**AND**
(sm___employee_skills.skill_id=5 AND sm___employee_skills.ans IN (3)))
AND
sm___employees.rating IN (1)
ORDER BY
sm___employee_skills.date DESC
When am using first query with OR of MBA or 3, It gives me result for both which is correct as per OR operation
I want only those records which are having MBA AND 3 which gives me blank records when there are records available with this comparison
So please help me to resolve this.
Thank you in advance
To start with: DISTINCT often indicates a badly written query. This is the case here. You are joining records only to dismiss them later. If you want employee records, then select from the employee table. If you have criteria on the skills table check this in the WHERE clause. Don't join.
Then the WHERE clause looks at one row at a time. So neither skill_id = ... AND skill_id = ... nor skill_id = ... OR skill_id = ... can work for you. You must look up the skills table twice:
SELECT
id,
employee_code,
leaving_date,
name_of_employee,
position,
rating,
entry_date
FROM sm___employees
WHERE rating IN (1)
AND id IN
(
SELECT employee_id
FROM sm___employee_skills
WHERE skill_id = 1 AND ans LIKE '%MBA%'
)
AND id IN
(
SELECT employee_id
FROM sm___employee_skills
WHERE skill_id = 5 AND ans IN (3)
);
And here is a way to look up skills just once:
SELECT
id,
employee_code,
leaving_date,
name_of_employee,
position,
rating,
entry_date
FROM sm___employees
WHERE rating IN (1)
AND id IN
(
SELECT employee_id
FROM sm___employee_skills
WHERE (skill_id = 1 AND ans LIKE '%MBA%')
OR (skill_id = 5 AND ans IN (3))
GROUP BY employee_id
HAVING COUNT(DISTINCT skill_id) = 2 -- both skills
);
It seems strange though that you consider ans to be a string in one place (ans LIKE '%MBA%') and a number in another (ans IN (3)).
UPDATE: If you want to sort by skill date, you should consider by which skill's date. For this to happen, you would join, but not join the skills table, but the skills aggregate result. E.g.:
SELECT
e.id,
e.employee_code,
e.leaving_date,
e.name_of_employee,
e.position,
e.rating,
e.entry_date
FROM sm___employees e
JOIN
(
SELECT employee_id, MAX(date) AS max_date
FROM sm___employee_skills
WHERE (skill_id = 1 AND ans LIKE '%MBA%')
OR (skill_id = 5 AND ans = 3)
GROUP BY employee_id
HAVING COUNT(DISTINCT skill_id) = 2 -- both skills
) s ON s.employee_id = e.id
WHERE e.rating = 1
ORDER BY s.max_date;
Please try this :
SELECT DISTINCT
sm1.id,
sm1.employee_code,
sm1.leaving_date,
sm1.name_of_employee,
sm1.position,
sm1.rating,
sm1.entry_date
FROM sm___employees sm1
LEFT JOIN sm___employee_skills sm2 ON sm1.id = sm2.employee_id
WHERE ((sm2.skill_id=1 AND sm2.ans LIKE '%MBA%')
AND (sm2.skill_id=1 AND sm2.ans=3))
AND sm1.rating IN (1)
ORDER BY sm2.date DESC;

mysql query group by totals

I am using the following query to retrieve the number of events per state from 2 tables that are linked by a userID.
SELECT state,COUNT(*) AS num
FROM tableUserInfo
WHERE userID IN (SELECT userID
FROM tableEvents
WHERE conditionOne = 1
AND conditionTwo = 2)
GROUP BY state
This query works correctly. My problem is that not all states have user entries, and I need the query to return 0 for those. I was wondering if there was a method such as joining or using an in clause, that would included a set of all states, making the query return 0 for any that didn't have entries in tableEvents?
Do you have a list of states? If not then this would give a list of all the states your database knows about:
SELECT DISTINCT state FROM tableUserInfo
....and enclosing this in brackets it can be dropped in place in the query below:
SELECT s.state, IFNULL(cnt, 0) AS num
FROM list_of_states s
LEFT JOIN (
SELECT state,COUNT(*) AS cnt
FROM tableUserInfo ui
INNER JOIN tableEvents te
ON ui.userId=te.userId
WHERE conditionOne = 1
AND conditionTwo = 2
GROUP BY state
) u
ON s.state=u.state;
Although in the absence of "list_of_states" it would be more efficient to do this:
SELECT ui.state, SUM(IF(te.userId IS NULL, 0, 1)) AS cnt
FROM tableUserInfo ui
LEFT JOIN tableEvents te
ON ui.userId=te.userId
AND te.conditionOne = 1
AND te.conditionTwo = 2
GROUP BY state;
As #raymond-nijland suggested you can use Left Join to include all states.
SELECT tableUserInfo.state,COUNT(tableUserInfo.*) AS num
FROM tableUserInfo Left Join tableEvents on tableUserInfo.userID = tableEvents.userID
WHERE tableEvents.conditionOne = 1 AND tableEvents.conditionTwo = 2
GROUP BY state

MS Access - Aggregate functions and max

I have this query, where I am trying to get max age of a retail store seller(There's multiple towns), and show multiple if there's multiple people with the same (max)age. I am using Microsoft Access 2010. Here is the query:
SELECT Linnad.Linn, Myyjad.Nimi, Max(Myyjad.Vanus) As Vanus
FROM Linnad INNER JOIN Myyjad ON Linnad.LinnID = Myyjad.LinnID
GROUP BY Linnad.Linn, Myyjad.Nimi
ORDER BY Linnad.Linn;
The problem is, it seems to ignore the MAX, and just shows all of the values, and I can't remove the group by Myyjad.Nimi, because it gives me an error that aggregate function not included for Myyjad.Nimi.
And the output should be:
Town - Name - Max(Age)
Also, Linn = Town, Nimi = Name and the Vanus = Age.
I think this may be what your looking for:
SELECT L.Linn, M.Nimi, M.Vanus
FROM Linnad As L,
(
SELECT M2.LinnID, M2.Nimi, M2.Vanus
FROM Myyjad As M2
WHERE M2.Vanus = (SELECT Max(Z.Vanus) FROM Myyjad As Z WHERE Z.LinnID = M2.LinnID)
) As M
WHERE M.LinnID = L.LinnID
This performs a sub-select to get a list of the Linn ID's with all Nimi's showing the maximum Vanus, then we link this sub-select back to the Linnad table via the LinnID.
I think you want:
SELECT Linnad.Linn, Myyjad.Nimi, Myyjad.Vanus
FROM Linnad INNER JOIN Myyjad ON Linnad.LinnID = Myyjad.LinnID
WHERE DateValue(Myyjad.Vanus)
= (SELECT Max(DateValue(Myyjad.Vanus)) FROM Myyjad)
ORDER BY Linnad.Linn
Top N per group:
SELECT Linnad.Linn, Myyjad.Nimi, Myyjad.Vanus
FROM FROM Linnad INNER JOIN Myyjad ON Linnad.LinnID = Myyjad.LinnID
WHERE Myyjad.ID In (
SELECT Top 1 m.ID
FROM Myyjad m
WHERE m.LinnID=Linnad.ID
ORDER BY m.Vanus Desc, m.ID)
Grouping by Linn (town) and Nimi (name) tells the db engine to give you one row for each combination of town and name, and show you the maximum Vanus (age) for each of those combinations. And logically, that's not what you want. You want the name of each person whose age is the same as the maximum age in that town.
First verify you can retrieve the max age for each LinnID.
SELECT
LinnID,
Max(Vanus) As MaxOfVanus
FROM
Myyjad
GROUP BY LinnID;
If that works, you can save it as "qryTownAge", then use it in another query where you join it (on LinnID) with Linnad. That will allow you to retrieve the matching Linn.
SELECT l.LinnID, l.Linn, q.MaxOfVanus
FROM
Linnad AS l
INNER JOIN qryTownAge AS q
ON l.LinnID = q.LinnID
ORDER BY l.Linn;
If that works, save it as qryTownAge2. Then try this query.
SELECT q.Linn, q.MaxOfVanus, m.Nimi
FROM
qryTownAge2 AS q
INNER JOIN Myyjad AS m
ON (
m.LinnID = q.LinnID
AND m.Vanus = q.MaxOfVanus
)
ORDER BY q.Linn;
If that all works, you could create a single query which does it all. However, doing it step by step should help us pinpoint errors.