SQL find the most recurring element based on different table relations - mysql

I have a question regarding how to do an SQL query. I wrote a sample database that I am using here, I am trying to keep things simple for all of you who wish to help.
Officer Permit Vehicle Dispatch
Oid | Dname | Rank Oid | Type | Model Vid | Type | Model Did | Oid | Location
------------------ ------------------ ------------------ --------------
1 | John | Jr 1 D1 Ford 1 D1 Ford 1 1 Hill
2 | Jack | Sr 1 D2 Ford 2 D2 Ford 2 2 Beach
3 | Jay | Jr 2 D1 Ford 3 D3 Ford 3 3 Post
4 | Jim | Jr 3 D1 Ford 4 D4 Ford 4 1 Beach
5 | Jules | Sr 5 D1 Ford 5 D5 Ford 5 2 Hill
1 D3 Ford 6 4 Post
2 D2 Ford 7 5 Hill
4 D1 Ford 8 5 Beach
1 D5 Ford 9 2 Post
The relation between the tables are:
Officer - lists the officer by OID(officer ID)/Name/Rank where Sr is highest, Jr is lowest.
Permit - Officers are required to have a permit depending on the vehicle they will be using, Oid for Officer ID, Type for the vehicle and Model.
Vehicle - Vid for vehicle ID, Type and Model
Dispatch - Did for Dispatch ID, keeps track of which officer (Oid) was dispatched to which location (Location)
Question: I need to know a couple of things from here.
First is how do I know which officer is permitted to drive all vehicle types?
Second is How do I know which officer has been dispatched to all the dispatched locations?
Writing these two queries has been a nightmare for me, I have tried to join different tables but I still cannot get the most recurring element from either (I don't know how!) any assistance will be much appreciated!

First question:
select Oid, count(*) type_count
from Permit
group by Oid
having type_count = (select count(distinct Type, Model) from Vehicle)
Second:
select Oid, count(*) location_count
from Dispatch
group by Oid
having location_count = (select count(distinct Location) from Dispatch)
See a pattern?

Related

The best way to Find entries missing after inner-join?

Lets suppose that we have the following 3 tables
Animal
id name
1 dog
2 cat
3 crow
Actions
id name
1 run
2 walk
3 jump
4 fly
5 puppy_eyes
6 swim
Animal_Actions
id Animal_id action_id
1 1 1
2 1 2
3 1 3
4 1 5
5 2 1
6 2 2
7 2 3
8 3 2
9 3 4
I would like to find all the missing animal actions for certain animals
For example if we input dog and cat( id 1 and 2) we should get the following (1,4),(1,6),(2,4),(2,5), (2,6)
and if we input crow (3) we get the following (3,1),(3,3),(3,5), (3,6) .
Currently I'm doing an inner join between Animal and Animal_Actions table based on animal ID and importing this into a SET in my code and checking if every possible permutation is present in this set and collecting the missing ones. I'm not sure if the process I follow is the most efficient one, is there a better way to do this when the data is at a large scale ? Thanks in advance.
If you'll be filtering on a small number of Animal records, one approach is to do a CROSS JOIN with the Actions table. That will give you all action combinations for each Animal record. Then do an OUTER JOIN to Animal_Actions to identify which ones are missing.
For example, using cat = 2 and dog = 1
SELECT ani.id AS Animal_Id
, ani.Name AS Animal_Name
, act.id AS Action_Id
, act.Name AS Action_Name
FROM Animal ani
CROSS JOIN Actions act
LEFT JOIN Animal_Actions aa ON ani.id = aa.Animal_id
AND aa.Action_Id = act.id
WHERE ani.id IN (1,2)
AND aa.id IS NULL
ORDER BY ani.Name, act.Name
;
Results:
Animal_Id | Animal_Name | Action_Id | Action_Name
--------: | :---------- | --------: | :----------
2 | cat | 4 | fly
2 | cat | 5 | puppy_eyes
2 | cat | 6 | swim
1 | dog | 4 | fly
1 | dog | 6 | swim
db<>fiddle here

How to delete rows using 2 different columns as condition in a SQL query?

My table is something like this:
Name Order Goods Date
------------------------------------------------
Michael 1 Shoes 2019/04/05
Michael 2 Groceries 2019/05/28
Michael 3 Caps 2019/03/02
Lucas 4 Shoes 2019/02/30
Lucas 5 Caps 2019/03/31
Mary 6 Shoes 2018/04/22
Mary 7 Shoes 2018/03/25
Mary 8 Groceries 2017/08/22
Mary 9 Caps 2019/01/01
How to define a query so that I can delete rows obeying the following conditions:
First and foremost I want to group everything by the Name column
Shoes is my reference. I need to check If any customer has bought "Shoes" and will keep any other Goods registered if and only if the buying date is earlier than the "Shoes" buying date of that customer (grouped by the Name column) (i.e if any good other than Shoes has been bought after the Shoes buying date, this any other good row will be deleted)
I keep only the first buying date of Shoes to compare. Newer dates are deleted too. Only the first one (older one) is kept.
So, I will have a table like below:
Michael 1 Shoes 2019/04/05
Michael 3 Caps 2019/03/02
Lucas 4 Shoes 2019/02/30
Mary 7 Shoes 2018/03/25
Mary 8 Groceries 2017/08/22
Thank you
You can join an aggregate query that computes the first date when each customer ordered shoes, and use that information to filter the rows to delete:
delete t
from mytable t
inner join (
select name, min(date) min_date
from mytable
where goods = 'Shoes'
group by name
) t1 on t.name = t1.name and t.date > t1.min_date
Demo on DB Fiddle:
Name | OrderID | Goods | Date
:------ | ------: | :-------- | :---------
Michael | 1 | Shoes | 2019-04-05
Michael | 3 | Caps | 2019-03-02
Lucas | 4 | Shoes | 2019-02-28
Mary | 7 | Shoes | 2018-03-25
Mary | 8 | Groceries | 2017-08-22

how to get ordered queries in mysql

I have 2 tables, animal and people, I am making a query using UNION to get a combined list of both tables, but I want every 4 animals I look 1 person, that is:
Results:
*animal 1
animal 2
animal 3
animal 4*
**person 1**
*animal 5
animal 6
animal 7
animal 8*
**person 2**
etc...
Is there any way to do it?
Please help me!
DEMO: using rextester
Using user variables you can often simulate analytics in enterprise databases (though not nearly as efficient)
We generate derived table (UnionSeq) to generate the needed sequencing and then add our own formula to multiply the generated row_number for persons to be 4 * greater so it will fit in after the 4th animal and use column aliased seq to determine that animals come before people in the order. Then we select from the derived table to apply the needed ordering.
SELECT Name
FROM (SELECT ID, Name, (#p:=#P+1)*4 Row_num, 'b' as Seq
FROM person
CROSS JOIN (SELECT #p:=0) a
UNION ALL
SELECT ID, Name, #a:=#a+1, 'a' as seq
FROM animal
CROSS JOIN (SELECT #a:=0) b) UnionSeq
ORDER BY Row_num, Seq
Giving us:
+----+----------+
| | Name |
+----+----------+
| 1 | Animal 1 |
| 2 | Animal 2 |
| 3 | Animal 3 |
| 4 | Animal 4 |
| 5 | Person 1 |
| 6 | Animal 5 |
| 7 | Animal 6 |
| 8 | Animal 7 |
| 9 | Animal 8 |
| 10 | Person 2 |
| 11 | Animal 9 |
| 12 | Person 3 |
+----+----------+
Your sample data doesn't show what to do if there are disproportionate numbers of people to animals; so in my demo I just let each table show all data based on a pattern irrespective if the 4x1 pattern can't be maintained. In this example you can see Animal 9 is followed by person 3 even though there aren't 4 animals. and if there was a person 4 it would follow person 3 as there would be no more animals.
It's not magic; it's math and general SQL processes and order of operations.

MySQL query with AND and OR in WHERE clause

I am creating a student records search query. The school has three clubs (maths, english and science). What i want to do is to select student by the club they have joined in this order.
Student who are in
-- Maths Only
-- Maths and English only
-- Maths and Science Only
-- English Only
-- English and Science Only
-- Science Only
Student table (studentTB)
id | student_name | date_join
-----------------------------
1 | Daniel Addo | 2012-01-05
2 |David Polles | 2013-05-11
3 | Grace Amorno | ---------
4 | Zein Akill | ---------
Club table (studentCLUB)
id | studentID | club
----------------------
1 | 1 | maths
2 | 1 | science
3 | 2 | science
4 | 2 | english
5 | 3 | science
6 | 4 | maths
7 | 4 | science
8 | 4 | english
SELECT *
FROM studentTB
INNER JOIN studentCLUB
ON studentTB.id = studentCLUB.studentID
WHERE (club = 'maths') OR (club = 'science') OR (day = 'english')
GROUP BY studentTB.id
This is what i have so far and it is selecting student when they fall within one of the club. But when i change the OR to AND it gives me null.
I will be glad if anyone can help me. Thank you
So it you need to find students who belongs to all the given club you can do as below. It will check the students having all the given 3 clubs.
SELECT *
FROM studentTB
INNER JOIN studentCLUB
ON studentTB.id = studentCLUB.studentID
WHERE
club in ('maths','science','english')
GROUP BY studentTB.id
having count(*) = 3
SELECT * FROM studentTB
WHERE EXISTS(SELECT * FROM studentCLUB
WHERE studentTB.id = studentCLUB.studentID)

MySql Query Optimization for parent child relationship

I am in trouble with large database with one of my query which is obvious not correct and I am not good in database side so I am not sure what I can do to optimize this query. Below is my table structure and details what data I need to fetch.
User Table
UserID UserName UserRole ParentID
1 ABC1 2 0
2 ABC2 2 0
3 ABC3 2 1
4 ABC4 2 1
5 ABC5 2 2
Survey Table Structure
SurveryID SurveyTitle UserID
1 S1 3
2 S2 3
3 S3 4
4 S4 4
3 S3 4
4 S4 5
3 S3 3
4 S4 5
3 S3 3
4 S4 4
The users which don't have parentID are Supervisors and who has parentID are Sales persons under that Parent supervisor.
So, I want to get list of Supervisor with their sales person with number os surveys they did. Something like below.
SuperVisorName SurveyCount
ABC1 10
ABC3 4
ABC4 6
ABC2 18
ABC5 18
In our current system, we first get all supervisors and then look through all supervisors to get their sales person with their surveys.
This make query very slow thus, resulting timeout error. We have 40k records for survey right now and hoping to grow more than 100k.
I searched little on that and we found Union can help in this but I am not sure how to apply in my scenario ? I guess this should be a single query to accomplish said result ?
Please let me know if you have any questions. I would clarify those.
Will appreciate your help on this. Thanks for your time.
Try this query
select
if(a.username is null, b.username, a.username) as username,
a.parentid, -----if(a.username is null, 0, a.parentid) parentid,
a.cnt -----Replace above line if you want value to be 0 of parentId
from
(select
parentid,
username,
count(*) cnt
from
tbl1 a
inner join
tbl2 b
on
a.userid = b.userid
group by
parentid,
username
with rollup) a
inner join
tbl1 b
on
a.parentid = b.userid
Results:
| USERNAME | PARENTID | CNT |
-----------------------------
| ABC3 | 1 | 4 |
| ABC4 | 1 | 4 |
| ABC1 | 1 | 8 |
| ABC5 | 2 | 2 |
| ABC2 | 2 | 2 |
SQL FIDDLE