Listing the results of an absentee list - mysql

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;

Related

MySQL Left Join throwing off my count numbers

I'm doing a left join on a table to get the number of leads we've generated today and how many times we've called those leads. I figured a left join would be the best thing to do, so I wrote the following query:
SELECT
COUNT(rad.phone_number) as lead_number, rals.lead_source_name as source, COUNT(racl.phone_number) as calls, SUM(case when racl.contacted = 1 then 1 else 0 end) as contacted
FROM reporting_app_data rad
LEFT JOIN reporting_app_call_logs racl ON rad.phone_number = racl.phone_number, reporting_app_lead_sources rals
WHERE DATE(rad.created_at) = CURDATE() AND rals.list_id = rad.lead_source
GROUP BY rad.lead_source;
But the problem with that, is that if in the reporting_app_call_logs table, there are multiple entries for the same phone number (so a phone number has been called multiple times that day), the lead_number (which I want to count how many leads were generated on the current day grouped by lead_source) equals how many calls there are. So the count from the LEFT table equals the count from the RIGHT table.
How do I write a SQL query that gets the number of leads and the total number of calls per lead source?
Try COUNT(DISTINCT expression)
In other words, change COUNT(rad.phone_number) to COUNT(DISTINCT rad.phone_number)

MySQL dynamic order

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

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

Print all rows from a nested Left Join + Union MySQL query

I have a query that calculates information for a revolving monthly retainer. The Project has a certain number of hours assigned to it each monthly period, with periods starting at different times of the month (e.g., February 5th to March 4th). The columns of the query result include:
Project Name
Total Hours Logged
Monthly Hours Remaining
Last Day of Period
Days Remaining
For example, Project A has 15 hours logged to it, with 5 hours remaining in the monthly period. The last day of the period is November 17th, with 3 days remaining from today.
The current Query takes 4 tables that are joined using a left join to print all of the Clients even if there are no hours logged, then it uses a nested subquery (lines 8-86) to calculate columns 2, 3, 4, and 5. However, column 4 and 5 do not print, they just show as always NULL. (Those are Last Day of Period and Days Remaining).
You can see the schema + query code at the SQL fiddle link here: http://sqlfiddle.com/#!2/fc830/12
How can I get column 4 and 5 to print the data and not be null when there are no Hours Logged? I think I may need an additional left join but I am not able to get a solution. If you have any suggestions it would be appreciated. Thanks!
When there has been no hours logged, the left join to the nested query returns nulls for the columns you're having trouble with.
The answer is to provide values for them when they are null and us ifnull() to use those value when the left join returns nulls:
select
...
ifnull(<left joined value>, <value when there's no join>),
...
See the working solution in sqlfiddle.
Incidentally, some values you are returning from the inner query, particularly the "last day" value can be derived directly from client (as seen in my solution). It's best to keep your queries as simple as possible - don't get data in a complicated way when there's an simpler or more direct way.
I think you are not thorough with the idea of LEFT JOIN. LEFT JOIN results in all rows from the outer table. Its otherwise called LEFT Outer JOIN (contrary to RIGHT OUTER JOIN). In your case the inner query results in only record with client id = 4. See the last clause X on X.id=client.id. Now what do you expect the results to be?
OUTER TABLE (client table)
id = 1, 2, 3, 4
INNER TABLE
client id = 4
ON X.id=client.id
An INNER JOIN would result in just one record since there is only matching record - for id = 4.
But a LEFT JOIN would result in all 4 records from outer table but the values for invalid fields will be NULL. Here except for client id 4, there is no valid records from inner table, hence they will be null.
To get more clarity you will have to see the id field along the records. Try this fiddle
You can see the other answer as to how to fill those NULL fields..