Select cars that are only driven by 19-year-olds - mysql

I want to get only the cars that are only driven by 19 year old persons
If I have these tables:
The result of the query would be only the Cars with the id = 1 and id = 4
I've tried
select d.IdCar
from Persons p, Drive d
where d.IdPerson = p.IdPerson and p.Age = 19
But it gave the cars that are driven by at least one person aged 19yo.

Try this:
SELECT c.IdCar, c.Brand
FROM Car c
INNER JOIN Drive d
USING (IdCar)
INNER JOIN Persons p
USING (IdPerson)
GROUP BY d.IdCar
HAVING MIN(p.Age) = 19
AND MAX(p.Age) = 19

You can use join to get the result. But suppose your database will have to grow rapidly then I will suggest you create VIEW.
You can create a sample view by using the below command.
CREATE VIEW drive_view as (
select d.IdCar, c.Brand, d.IdPerson, p.Name, p.Age from drive d
left join Persons p on d.IdPerson = p.IdPerson
left join CARS.c on d.IdCar = c.IdCar
order by p.IdPerson ASC
);
Then you have just use SELECT the query from your program. e.g.
select * from drive_view where Age = 19;
I hope this helps. If you are at the beginning stage, I will recommend you to get some knowledge about Joins, View, Trigger, etc. It will help you a lot.

So I found this solution, and it worked for me:
So we first create a view of the dirvers with age != 19
CREATE VIEW drive_view as (
select d.IdPerson from drive d
left join Persons p on d.IdPerson = p.IdPerson
left join CARS.c on d.IdCar = c.IdCar
Where P.age <> 19
);
Then we do this query:
SELECT D.IdCar FROM Drive d JOIN Person P ON d.IdPerson = p.IdPerson WHERE p.age = 19
AND P.IdPerson NOT IN (SELECT * FROM drive-view)
So it's basically the inverse idea of #Yash: Select cars that are only driven by 19-year-olds
Wich gave all the cars that are driven by at least a 19 yo person.

Related

MySQL, select, comparing values from 2 tables

in my database I want to select every construction_manual
where storage_room.quantity > component.quantity
But when I use:
SELECT construction_manual.name
FROM construction_manual cm, construction_manual_component cmc, component, storage_room
WHERE cm.ID = cmc.construction_manual_ID
AND cmc.component_ID = component.ID
AND component.storage_room_ID = storage_room.ID
AND storage_room.quantity > component.quantity
It will select every construction_manual.name as long as the first component in the storage_room has enough quantity.
So let's say...
construction_manual.1 needs
component.A -> quantity 5
component.B -> quantity 10
and in the storage room there is:
component.A -> quantity 6
component.B -> quantity 0
Although there is not enough in the storage room, construction_manual.1 will be selected. How do I select only those construction_manuals where there are enough components in the storage_room?
edit:
In my 4 tables are the following datasets. I will get the following result when I use the query mentioned above:database . But I should not be able to construct a table because there are not enough wooden_plates (wooden planks and not wooden plates ofc...ups)
I think what you want to ask is to ignore or exclude any construction manual that does not have enough components to satisfy a build. If that's the case you can do something like the below (a left join would also do it):
select distinct cm.name as construction_manual
from construction_manual cm
join construction_manual_component cmc
on cmc.construction_manual_ID = cm.ID
join component c
on c.ID = cmc.component_ID
join storage_room sr
on sr.ID = c.storage_room_ID
where sr.quantity > c.quantity
and cm.ID not in (select cm.ID
from construction_manual cm
join construction_manual_component cmc
on cmc.construction_manual_ID = cm.ID
join component c
on c.ID = cmc.component_ID
join storage_room sr
on sr.ID = c.storage_room_ID
where sr.quantity < c.quantity);

SQL: SELECT where 2 columns from different tables are the same

I need to work with a database that contains info about (former) Presidents. I need to check if there a presidents that have the same hobbies AND are married in the same year.
So a president can have multiple hobbies in pres_hob table. And the marriage year is in the pres_mar table, in the mar_year column.
I've tried to INNER JOIN the tables in SQLite where the hobby and mar_year are equal, except for the pres_name. This way the JOIN doesnt work ofcourse, which makes sense. Im kinda new to this..
Any help is appreciated
Here's one option with multiple joins:
select p1.pres_name, p2.pres_name, ph.hobby
from pres_mar p1
join pres_mar p2 on p1.pres_name != p2.pres_name and p1.mar_year = p2.mar_year
join pres_hob ph on p1.pres_name = ph.pres_name
join pres_hob ph2 on p2.pres_name = ph2.pres_name and ph.hobby = ph2.hobby
And depending on your expected results, another option using exists:
select pm.pres_name, ph.hobby
from pres_mar pm
join pres_hob ph on pm.pres_name = ph.pres_name
where exists (
select 1
from pres_mar pm2
join pres_hob ph2 on pm2.pres_name = ph2.pres_name
where pm.pres_name != pm2.pres_name and
ph.hobby = ph2.hobby
)
That sounds like a terrible database schema, I'm assuming its for learning purposes, anyway, you could do something like
SELECT
h.name,
h.hobby,
m.year
FROM
pres_hob h,
pres_mar m
WHERE
h.hobby = 'tennis'
AND
m.year = 2016
This would return 1 record for every president with a marriage year of 2016 , and a hobby of Tennis.

Update Table by Join and Group by

A Company has many Reviews which has Rating Column itself.
CompID Ratig
12 3
13 3
17 4
22 4
23 5
24 3
28 3,2
This is what I need to be set to each company by id. Now Rating In Company Column is NULL.
I've written something like this:
UPDATE Companies c
JOIN Reviews r on c.CompanyID = r.CompanyID
SET c.Rating = AVG(r.rating)
group by r.CompanyID
This should do what you want using a simple nested query, in this case probably simpler than a JOIN.
UPDATE Companies
SET Rating =
(SELECT AVG(Rating)
FROM Ratings
WHERE Companies.CompanyId = Ratings.CompId)
Simple SQLfiddle demo here.
EDIT: If you really want to use a JOIN/UPDATE FROM, it'd look something like this;
UPDATE c
SET c.Rating = r.Rating
FROM Companies c
JOIN (SELECT AVG(Rating) Rating, CompID FROM Ratings GROUP BY CompId) r
ON c.CompanyId = r.CompId
At least to me, somewhat more complicated to read, and afaik it only works on SQL Server, but here's the SQLfiddle for that too :)
UPDATE ComisionesxColaboradorxLineaPrescripciones
SET CANTIDAD_PRODUCTOS_CORE_CUMPLE = CANTIDAD
FROM #ComisionesxColaboradorxLineaPrescripciones ComisionesxColaboradorxLineaPrescripciones
INNER JOIN
(SELECT TAB_L.COD_COLAB AS COD_COLAB,TAB_L.TIPO_COLABORADOR AS TIPO_COLABORADOR, COUNT(TAB_P.COD_SEG) AS CANTIDAD
FROM #ComisionesxColaboradorxLineaPrescripciones TAB_L
INNER JOIN #ComisionesxColaboradorxLineaxProductoPrescripciones TAB_P
ON TAB_L.COD_COLAB=TAB_P.COD_COLAB AND
TAB_L.TIPO_COLABORADOR=TAB_P.TIPO_COLABORADOR
GROUP BY TAB_L.COD_COLAB,TAB_L.TIPO_COLABORADOR
) AGRUPADO
ON ComisionesxColaboradorxLineaPrescripciones.COD_COLAB = AGRUPADO.COD_COLAB AND
ComisionesxColaboradorxLineaPrescripciones.TIPO_COLABORADOR = AGRUPADO.TIPO_COLABORADOR

SQL Query filtering advice

I'm not sure what I'm trying to do is possible but I've been trying to get different methods to a solution I need but so far I've come up empty handed.
Lets say I have 2 tables (just an example, in my case theres a hell of a lot more + alot more data)
One called clients and the other called form_data.
We have multiple clients in the clients table and in the form_data table we have multiple rows for each company present in the clients table. In form_data we store the serialized data from different forms. (id and data)
I'm currently pulling all records from the form_data table and I am trying to use a regexp on the data column to filter for instance that the value 'motor oil' is found in them.
I would like a way to do this filter but filter the company and not the forms .. so I want to find the forms that have 'motor oil' in them and the remove all entries for COMPANIES that don't have this match, but I want to keep all the forms showing for the companies that match.
I can post my query but it is rather long and i think if we can solve the above it should be sufficient for me to implement into the actual query.
Regards
EDIT:
SELECT f.form_question_has_answer_id AS f__form_question_has_answer_id, f.form_question_has_answer_request AS f__form_question_has_answer_request,
f.form_question_has_answer_form_id AS f__form_question_has_answer_form_id, f.form_question_has_answer_user_id AS f__form_question_has_answer_user_id,
p.project_company_has_user_id AS p__project_company_has_user_id, p.project_company_has_user_project_id AS p__project_company_has_user_project_id,
p.project_company_has_user_user_id AS p__project_company_has_user_user_id, c.company_id AS c__company_id, c.company_hall_no AS c__company_hall_no,
c.company_type AS c__company_type, c.company_company_name AS c__company_company_name, c.company_country AS c__company_country,
c.company_stand_number AS c__company_stand_number, c.company_image_file_1 AS c__company_image_file_1, p2.project_id AS p2__project_id,
p2.project_name AS p2__project_name, u.user_id AS u__user_id, u.user_username AS u__user_username, f2.form_id AS f2__form_id
FROM form_question_has_answer f
INNER JOIN project_company_has_user p ON f.form_question_has_answer_user_id = p.project_company_has_user_user_id
INNER JOIN company c ON p.project_company_has_user_company_id = c.company_id
INNER JOIN project p2 ON p.project_company_has_user_project_id = p2.project_id
INNER JOIN user u ON p.project_company_has_user_user_id = u.user_id
INNER JOIN form f2 ON p.project_company_has_user_project_id = f2.form_project_id
WHERE f.form_question_has_answer_id IN ('19262', '21560', '23088', '22660', '14772', '18495', '18720', '21625', '19957', '20943')
AND ((f2.form_template_name = "custom" AND p.project_company_has_user_garbage_collection = 0 AND p.project_company_has_user_project_id = 29) AND f.form_question_has_answer_request REGEXP 'item-cadcae')
ORDER BY company_company_name asc
The query is from a doctrine query.
EDIT:
If i have a company with 10 forms in the form_data table if i filter by 'motor oil' all forms for that company that don't have motor oil are removed.. so if only 1 of the 10 forms for company id 144 has the word motor oil then the other 9 forms are lost in the query.. I want to keep them. What I want is any company that didn't find any forms with that match (motor oil) to have all their forms removed from the search.
All form data for all customers who have at least one form that matches the search:
SELECT * FROM `form_data`
WHERE `clientid` IN (
SELECT DISTINCT `clientid` FROM `form_data`
WHERE `data` RLIKE '[[:<:]]motor oil[[:>:]]'
);
SELECT
c.*
FROM
clients as c
INNER JOIN (
select
*
from
forms
where
sometext like '%motor oil%'
) as f
ON f.client = c.id
http://sqlfiddle.com/#!3/5b616/1
in this part:
select
*
from
forms
where
sometext like '%motor oil%'
you can put any query that selects the relevant rows from your forms table with the appropriate filters.
you can do the inverse too with a left outer join where null technique.. though in this case modifying the subquery to return a list of distinct clients will probably give you more like the results you expect:
SELECT
c.*
FROM
clients as c
LEFT OUTER JOIN (
select
distinct
client
from
forms
where
sometext like '%motor oil%'
) as f
ON f.client = c.id
where f.client is null
http://sqlfiddle.com/#!3/5b616/4
so with your query something like:
SELECT
c.*
FROM
company AS c
INNER JOIN (
SELECT
DISTINCT c.company_id
FROM
form_question_has_answer f
INNER JOIN project_company_has_user p
ON f.form_question_has_answer_user_id = p.project_company_has_user_user_id
INNER JOIN company c
ON p.project_company_has_user_company_id = c.company_id
INNER JOIN project p2
ON p.project_company_has_user_project_id = p2.project_id
INNER JOIN user u
ON p.project_company_has_user_user_id = u.user_id
INNER JOIN form f2
ON p.project_company_has_user_project_id = f2.form_project_id
WHERE
f.form_question_has_answer_id IN ('19262', '21560', '23088', '22660', '14772', '18495', '18720', '21625', '19957', '20943')
AND ((f2.form_template_name = "custom"
AND p.project_company_has_user_garbage_collection = 0
AND p.project_company_has_user_project_id = 29)
AND f.form_question_has_answer_request REGEXP 'item-cadcae')
ORDER BY company_company_name asc
) as f
ON f.company_id= c.id
Not sure What do you mean by keeping all the forms showing for the companies that match?
Aren't just getting at this...
select * from clients inner join form_data on clients.id = form_data.id where form_data.[data] like '%motor oil%'
This will return all forms with 'motor oil' in them filled for the companies which also have 'motor oil' in their name:
SELECT *
FROM clients c
JOIN form_data fd
ON fd.client = c.id
WHERE fd.data RLIKE '[[:<:]]motor oil[[:>:]]'
AND c.name RLIKE '[[:<:]]motor oil[[:>:]]'

SQL: Get latest entries from history table

I have 3 tables
person (id, name)
area (id, number)
history (id, person_id, area_id, type, datetime)
In this tables I store the info which person had which area at a specific time. It is like a salesman travels in an area for a while and then he gets another area. He can also have multiple areas at a time.
history type = 'I' for CheckIn or 'O' for Checkout.
Example:
id person_id area_id type datetime
1 2 5 'O' '2011-12-01'
2 2 5 'I' '2011-12-31'
A person started traveling in area 5 at 2011-12-01 and gave it back on 2011-12-31.
Now I want to have a list of all the areas all persons have right now.
person1.name, area1.number, area2.number, area6.name
person2.name, area5.number, area9.number
....
The output could be like this too (it doesn't matter):
person1.name, area1.number
person1.name, area2.number
person1.name, area6.number
person2.name, area5.number
....
How can I do that?
This question is, indeed, quite tricky. You need a list of the entries in history where, for a given user and area, there is an 'O' record with no subsequent 'I' record. Working with just the history table, that translates to:
SELECT ho.person_id, ho.area_id, ho.type, MAX(ho.datetime)
FROM History AS ho
WHERE ho.type = 'O'
AND NOT EXISTS(SELECT *
FROM History AS hi
WHERE hi.person_id = ho.person_id
AND hi.area_id = ho.area_id
AND hi.type = 'I'
AND hi.datetime > ho.datetime
)
GROUP BY ho.person_id, ho.area_id, ho.type;
Then, since you're really only after the person's name and the area's number (though why the area number can't be the same as its ID I am not sure), you need to adapt slightly, joining with the extra two tables:
SELECT p.name, a.number
FROM History AS ho
JOIN Person AS p ON ho.person_id = p.id
JOIN Area AS a ON ho.area_id = a.id
WHERE ho.type = 'O'
AND NOT EXISTS(SELECT *
FROM History AS hi
WHERE hi.person_id = ho.person_id
AND hi.area_id = ho.area_id
AND hi.type = 'I'
AND hi.datetime > ho.datetime
);
The NOT EXISTS clause is a correlated sub-query; that tends to be inefficient. You might be able to recast it as a LEFT OUTER JOIN with appropriate join and filter conditions:
SELECT p.name, a.number
FROM History AS ho
JOIN Person AS p ON ho.person_id = p.id
JOIN Area AS a ON ho.area_id = a.id
LEFT OUTER JOIN History AS hi
ON hi.person_id = ho.person_id
AND hi.area_id = ho.area_id
AND hi.type = 'I'
AND hi.datetime > ho.datetime
WHERE ho.type = 'O'
AND hi.person_id IS NULL;
All SQL unverified.
You're looking for results where each row may have a different number of columns? I think you may want to look into GROUP_CONCAT()
SELECT p.`id`, GROUP_CONCAT(a.`number`, ',') AS `areas` FROM `person` a LEFT JOIN `history` h ON h.`person_id` = p.`id` LEFT JOIN `area` a ON a.`id` = h.`area_id`
I haven't tested this query, but I have used group concat in similar ways before. Naturally, you will want to tailor this to fit your needs. Of course, group concat will return a string so it will require post processing to use the data.
EDIT I thikn your question has been edited since I began responding. My query does not really fit your request anymore...
Try this:
select *
from person p
inner join history h on h.person_id = p.id
left outer join history h2 on h2.person_id = p.id and h2.area_id = h.area_id and h2.type = 'O'
inner join areas on a.id = h.area_id
where h2.person_id is null and h.type = 'I'