MySQL dynamic order - mysql

In general, all I need to do is to order a MySQL table.
But, it has to be a "smart" order and I would like to hear your opinions.
There is a table of customers
id, name, email, phone, country, language, registration_time
There is another table which holds the skills of sales managers as numeric values -
sales_manager_id, skill_type, skill_name, skill_value
7, language , English , 5
Which means that manager number 7 speaks English on level 5.
Every sales manager can have multiple skills.
Now, I want to order the customers table by country, language and registration_time (in this exact order) for a specific sales manager in such a way that the top rows will be from a country in which this sales manager has highest skills, after this by language in which he has the highest skills and after this by registration time.
Do you have any suggestions? The biggest problem is that this query should be simple and readable as much as possible because there would be modifications in the future and I don't want to deal with enormous queries.

I assume I understand your problem. If not please correct me, else here is my solution.
I did a few changes to your tabels in order to test the query and you can test my solution like I did here: SQL Fiddle
(1) You need to JOIN your customers table two times with the skills table - first for the country skill and second for the language skill of a sales manager:
select *
from customers
join skills as country_skills on country_skills.skill_name = customers.country
join skills as language_skills on language_skills.skill_name = customers.language
(2) You need to restrict your results for just the sales manager you want, e.g. sales manager with id = 11:
where country_skills.sales_manager_id = 11
and language_skills.sales_manager_id = 11
(3) The 'dynamic' order you want:
order by country_skills.skill_value desc, language_skills.skill_value desc, regTime desc
This would be my complete query:
select *
from customers
join skills as country_skills on country_skills.skill_name = customers.country
join skills as language_skills on language_skills.skill_name = customers.language
where country_skills.sales_manager_id = 11
and language_skills.sales_manager_id = 11
order by country_skills.skill_value desc, language_skills.skill_value desc, regTime desc
So you got all customers sorted by country skills of a specific sales manager > language skills of a specifiy sales manager > regTime of customer.
This query ignores customers with a country or language the sales manager got no skill... you can avoid that with a LEFT JOIN

Related

Listing the results of an absentee list

I am trying to produce a query that will generate a list of absent students whenever a my code is typed. The problem I am running into is that the output list is displaying none of the names of the students that were in class. My goal is to only list students that are over 30 days according to their most recent recorded date of attendance. Students that are not over 30 days will not be shown at all. It seems pretty simple enough however I'm running into a block. Is there a Syntax or two that I am missing?
SELECT trim(concat(name.fname,' ' ,name.mname,' ',name.lname)) as student, name.noiid as stuID, sum(meeting.meefoiid) as NO_CLASS, squadlt.ltfname as Squad
FROM name
LEFT JOIN meeting ON name.foiid = meeting.meefoiid
LEFT JOIN squadlt ON name.squadlt = squadlt.ltid
WHERE meeting.meefoiid IS NULL
AND MEEDATE >= '2014-09-12'
AND name.city = 'RICHMOND'
GROUP BY student
ORDER BY name.squadlt, student;

Relational Database Logic

I'm fairly new to php / mysql programming and I'm having a hard time figuring out the logic for a relational database that I'm trying to build. Here's the problem:
I have different leaders who will be in charge of a store anytime between 9am and 9pm.
A customer who has visited the store can rate their experience on a scale of 1 to 5.
I'm building a site that will allow me to store the shifts that a leader worked as seen below.
When I hit submit, the site would take the data leaderName:"George", shiftTimeArray: 11am, 1pm, 6pm (from the example in the picture) and the shiftDate and send them to an SQL database.
Later, I want to be able to get the average score for a person by sending a query to mysql, retrieving all of the scores that that leader received and averaging them together. I know the code to build the forms and to perform the search. However, I'm having a hard time coming up with the logic for the tables that will relate the data. Currently, I have a mysql table called responses that contains the following fields,
leader_id
shift_date // contains the date that the leader worked
shift_time // contains the time that the leader worked
visit_date // contains the date that the survey/score was given
visit_time // contains the time that the survey/score was given
score // contains the actual score of the survey (1-5)
I enter the shifts that the leader works at the beginning of the week and then enter the survey scores in as they come in during the week.
So Here's the Question: What mysql tables and fields should I create to relate this data so that I can query a leader's name and get the average score from all of their surveys?
You want tables like:
Leader (leader_id, name, etc)
Shift (leader_id, shift_date, shift_time)
SurveyResult (visit_date, visit_time, score)
Note: omitted the surrogate primary keys for Shift and SurveyResult that I would probably include.
To query you join shifts and surveys group on leader and taking the average then jon that back to leader for a name.
The query might be something like (but I haven;t actually built it in MySQL to verify syntax)
SELECT name
,AverageScore
FROM Leader a
INNER JOIN (
SELECT leader_id
, AVG(score) AverageScore
FROM Shift
INNER JOIN
SurveyResult ON shift_date = visit_date
AND shift_time = visit_time --depends on how you are recording time what this really needs to be
GROUP BY leader ID
) b ON a.leader_id = b.leader_id
I would do the following structure:
leaders
id
name
leaders_timetabke (can be multiple per leader)
id,
leader_id
shift_datetime (I assume it stores date and hour here, minutes and seconds are always 0
survey_scores
id,
visit_datetime
score
SELECT l.id, l.name, AVG(s.score) FROM leaders l
INNER JOIN leaders_timetable lt ON lt.leader_id = l.id
INNER JOIN survey_scores s ON lt.shift_datetime=DATE_FORMAT('Y-m-d H:00:00', s.visit_datetime)
GROUP BY l.id
DATE_FORMAT here helps to cut hours and minutes from visit_datetime so that it could be matched against shift_datetime. This is MYSQL function, so if you use something else you'll need to use different function
Say you have a 'leader' who has 5 survey rows with scores 1, 2, 3, 4 and 5.
if you select all surveys from this leader, sum the survey scores and divide them by 5 (the total amount of surveys that this leader has). You will have the average, in this case 3.
(1 + 2 + 3 + 4 + 5) / 5 = 3
You wouldn't need to create any more tables or fields, you have what you need.

Calculate a variable using 2 Mysql tables and make a select based on that variable

I own an online game in which you become the coach of a rugby team and I recently started to optimize my database. The website uses CodeIgniter framework.
I have the following tables (the tables have more fields but I posted only those which are important now):
LEAGUES: id
STANDINGS: league_id, team_id, points
TEAMS: id, active
Previously, I was having in the LEAGUES table a field named teams. This was representing the number of active teams in that league (of which users logged in recently).
So, I was doing the following select to get a random league that has between 0 and 4 active teams (leagues with less teams first).
SELECT id FROM LEAGUES WHERE teams>0 AND teams<4 ORDER BY teams ASC, RAND( ) LIMIT 1
Is there any way I can do the same command now without having to add the teams field?
Is it efficient? Or It's better to keep the teams field in the database?
LATER EDIT
This is what I did until now:
function test()
{
$this->db->select('league_id, team_id');
$this->db->join('teams', 'teams.id = standings.team_id');
$this->db->where('active', 0);
$query = $this->db->get('standings');
return $query->result_array();
}
The function returns all inactive teams alongside with their league_id.
Now how do I count the number of inactive teams in each league and how to I sort them after this number?
Try this:
select league_id
from standings s
join teams t on t.id = s.team_id and t.active
group by 1
having count(*) < 5

SQL Select statement from multiple tables while adding values

I'm having a bit of trouble figuring out a good statement to write. I am able to achieve what I want when I query a specific 'Company' but I wanting to get the values for all of the companies in the database.
Basically I have 3 tables: Users, Companies, Plans_ExchangeMailbox. What I need to do is query how many plans are in use for each company. The plans are assigned at the user level in the users table.
Here is my table layouts:
USERS
DisplayName
CompanyCode (This is the ID from the CompanyCode in the Companies table)
MailboxPlan (This is the ID from the Plans_ExchangeMailbox Table)
Companies
CompanyName
CompanyCode
Plans_ExchangeMailbox
MailboxPlanName
MailboxPlanID
Here is the format I am looking to generate:
CompanyName, MailboxPlanName, Count (this is the number of MailboxPlanID for a company)
I was able to get this working but the problem is it can only do one company at a time and it doesn't get the CompanyName:
SELECT
Plans_ExchangeMailbox.MailboxPlanName,
SUM(CASE WHEN Users.MailboxPlan = Plans_ExchangeMailbox.MailboxPlanId THEN 1 ELSE 0 END) AS PlanCount
FROM
Plans_ExchangeMailbox, Users
WHERE
Users.CompanyCode='CC0'
GROUP BY
Plans_ExchangeMailbox.MailboxPlanName
The Final Format How it Should Be:
Headers: CompanyName, PlanName, Count
Values:
Microsoft, Bronze Plan, 5
Microsoft, Gold Plan, 20
Dell, Bronze Plan, 3
Dell, Silver Plan, 80
etc.....
Try this:
SELECT
C.CompanyName,
E.MailboxPlanName,
COUNT(1) Cnt
FROM Companies C
JOIN Users U
ON C.CompanyCode = U.CompanyCode
JOIN Plans_ExchangeMailbox E
ON U.MailboxPlan = E.MailboxPlanID
GROUP BY
C.CompanyCode,
C.CompanyName,
E.MailboxPlanID,
E.MailboxPlanName
Grouped by C.CompanyCode and E.MailboxPlanID in case if there are different companies or MailboxPlan with same name. If no,you can remove them from GROUP BY clause.

MySQL relational database query, correct terminology?

I think my issue with databases stems from not knowing the correct terminology to help me find an answer myself so I'll explain a generic version of what I'm doing and hopefully you can point some tutorials my way or give me some terms to check into.
Let's use an example of an employee directory.
Each employee can have multiple locations, multiple job duties which pull from a separate table. Example tables & some data, let's just focus on the multiple locations.
employees
Main employee data
- id (ex: 400)
- first (ex: John)
- last (ex: Doe)
locations
Unique list of locations
- id (ex: 3000)
- title (ex: FakeCo, LLC)
map_employees_locations
Tie ANY number of locations to an employee
- id
- employee_id (ex: 400)
- location_id (ex: 3000)
I'm struggling with the logic of how a single query would return something like this:
John
Doe
FakeCo, LLC
AnotherCo, LLC
It seems I would have to run a query to get the employee data, then within a nested query, grab locations associated with the employee id, etc... If there was only one location per employee, it would be a simple join, I just don't know how to handle the multiples.
Let me know if I'm way off, I'm just struggling.
You would join all of the tables together like this
select e.id,e.first,e.last,l.id,l.title
from employees e
inner join map_employees_locations el
on el.employee_id = e.id
inner join locations l
on el.location_id = l.id
where e.first = 'John'
AND e.last = 'Doe'
This would return data like this:
e.id e.first e.last l.id l.title
------------------------------------------------
1 John Doe 1 FakeCo, LLC
1 John Doe 2 AnotherCo, LLC
If you want only one line per employee you should maybe use group concat
select id, e.last, e.first
group_concat(l.title separator ',' ) as locations
from employee e
join location l on l.employee_id = e.id
group by e.id
Not sure about the syntax cos i'm more aware of postgres but this should do the job.