MySQL JOIN is ignoring COUNT in results - mysql

I'm trying to do a JOIN like you see below. I only want records that have at least X email addresses in the property_res table. When I change the acount value from 10 to 20 for example the returned results stay at 949 records. This should decrease dramatically as there should be alot less matches where r.EmailAddress is found 20 times. Is there a limitation to using COUNT on a varchar data type? What is the best way to achieve this?
SELECT
r.FirstName AS ag_fname,
r.LastName AS ag_lname,
r.EmailAddress AS ag_email,
COUNT(r.EmailAddress) AS `acount`
FROM property_res e
LEFT JOIN ActiveAgent_Matrix r
ON e.ListAgentMLSID=r.MemberNumber
WHERE e.ListPrice >= 50000
GROUP BY r.EmailAddress
HAVING acount >=20
A sample output of the data shows a weird value for acount as I'd think it would be the count of the email address but they all are the same?
ag_fname | ag_lname | ag_email | acount
Jane | Doe1 | jdoe1#doe.com | 3390
Jane | Doe3 | jdoe3#doe.com | 3390
Jane | Doe4 | jdoe4#doe.com | 3390
Jane | Doe5 | jdoe5#doe.com | 3390

What's happening is your join condition is not specific enough (or in fact multiple emails can be associated with the same id, or vice versa, in which case you GROUP BY is not specific enough). I suspect it is the former and that your result set is exploding. Not quite a Cartesian join, but similar.
Try to troubleshoot with the following two queries:
SELECT
r.EmailAddress,
COUNT(*)
FROM property_res e
LEFT JOIN ActiveAgent_Matrix r
ON e.ListAgentMLSID=r.MemberNumber
GROUP BY r.EmailAddress
HAVING COUNT(*) > 1;
SELECT
e.ListAgentMLSID,
COUNT(*)
FROM property_res e
LEFT JOIN ActiveAgent_Matrix r
ON e.ListAgentMLSID=r.MemberNumber
GROUP BY e.ListAgentMLSID
HAVING COUNT(*) > 1;
One (or both) of these result sets will be non empty. That's important because it means that this join condition: ON e.ListAgentMLSID=r.MemberNumber is not specific enough. Either there are multiple emails per ListAgentMLSID or there are multiple ListAgentMLSID's per email address... or both.
To trouble shoot this, I'd start by trying to identify where the "multiple X's per Y's" are. The queries above should actually help you do that. The first one will identify emails associated with multiple IDs. The second will help you identify IDs associated with multiple emails. The question you need to ask yourself is, should multiple emails be associated with any given id? Or should multiple ids be associated with any given email? If that's permissible, change your GROUP BY. If it's not, change your join condition.
It may be as simple as joining on id and email.... but if it is not, then you either need to group by the email as well (as suggested above in the comments... this is fine if indeed multiple emails should be permitted to have an association with an id, or vice versa) or you need to add an additional join condition that's specific enough to prevent data that shouldn't be joined, joined.
Hope this helps.

Related

what does this sql query do? SELECT column_1 FROM table_1,table_2;

SELECT column_1 FROM table_1,table_2;
When I ran this on my database it returned huge number of rows with duplicate column_1 values. I could not understand why I got these results. Please explain what this query does.
it gives you a cross product from table 1 and table 2
In more layman's terms, it means that for each record in Table A, you get every record from Table B (all possible combinations).
TableA with 3 records and Table B with 3 records gives 9 total records in the result:
TableA-1/B-1
TableA-1/B-2
TableA-1/B-3
TableA-2/B-1
TableA-2/B-2
TableA-2/B-3
TableA-3/B-1
TableA-3/B-2
TableA-3/B-3
Often used as a basis for Cartesian Queries (which themselves are the means to generate, say, a list of future dates based on a recurrence schedule: give me all possible results for the next 6 months, then restrict that set to those whose factor matches my day of the week)
This is 'valid' way of cross joining two tables; it is not the preferred way though. Cross Join would be much clearer. An on condition would then be helpful to limit results,
Imagine that i have 3 friends named Jhon, Ana, Nick; then i have in the other table 2 are T-shirts a red and a yellow and i wanna know witch is from.
So in the query being tableA:Friends and tableB:Tshirts returns:
1|JHON | t-shirt_YELLOW
2|JHON | t-shirt_RED
3|ANA | t-shirt_YELLOW
4|ANA | t-shirt_RED
5|NICK | t-shirt_YELLOW
6|NICK | t-shirt_RED
As you see this join has no relational logic between friends and Tshirts so by evaluating all the posible combination generates what you call duplicates.

Joining and selecting multiple tables and creating new column names

I have very limited experience with MySQL past standard queries, but when it comes to joins and relations between multiple tables I have a bit of an issue.
I've been tasked with creating a job that will pull a few values from a mysql database every 15 minutes but the info it needs to display is pulled from multiple tables.
I have worked with it for a while to figure out the relationships between everything for the phone system and I have discovered how I need to pull everything out but I'm trying to find the right way to create the job to do the joins.
I'm thinking of creating a new table for the info I need, with columns named as:
Extension | Total Talk Time | Total Calls | Outbound Calls | Inbound Calls | Missed Calls
I know that I need to start with the extension ID from my 'user' table and match it with 'extensionID' in my 'callSession'. There may be multiple instances of each extensionID but each instance creates a new 'UniqueCallID'.
The 'UniqueCallID' field then matches to 'UniqueCallID' in my 'CallSum' table. At that point, I just need to be able to say "For each 'uniqueCallID' that is associated with the same 'extensionID', get the sum of all instances in each column or a count of those instances".
Here is an example of what I need it to do:
callSession Table
UniqueCallID | extensionID |
----------------------------
A 123
B 123
C 123
callSum table
UniqueCallID | Duration | Answered |
------------------------------------
A 10 1
B 5 1
C 15 0
newReport table
Extension | Total Talk Time | Total Calls | Missed Calls
--------------------------------------------------------
123 30 3 1
Hopefully that conveys my idea properly.
If I create a table to hold these values, I need to know how I would select, join and insert those things based on that diagram but I'm unable to construct the right query/statement.
You simply JOIN the two tables, and do a group by on the extensionID. Also, add formulas to summarize and gather the info.
SELECT
`extensionID` AS `Extension`,
SUM(`Duration`) AS `Total Talk Time`,
COUNT(DISTINCT `UniqueCallID`) as `Total Calls`,
SUM(IF(`Answered` = 1,0,1)) AS `Missed Calls`
FROM `callSession` a
JOIN `callSum` b
ON a.`UniqueCallID` = b.`UniqueCallID`
GROUP BY a.`extensionID`
ORDER BY a.`extensionID`
You can use a join and group by
select
a.extensionID
, sum(b.Duration) as Total_Talk_Time
, count(b.Answered) as Total_Calls
, count(b.Answered) -sum(b.Answered) as Missed_calls
from callSession as a
inner join callSum as b on a.UniqueCallID = b.UniqueCallID
group by a.extensionID
This should do the trick. What you are being asked to do is to aggregate the number of and duration of calls. Unless explicitly requested, you do not need to create a new table to do this. The right combination of JOINs and AGGREGATEs will get the information you need. This should be pretty straightforward... the only semi-interesting part is calculating the number of missed calls, which is accomplished here using a "CASE" statement as a conditional check on whether each call was answered or not.
Pardon my syntax... My experience is with SQL Server.
SELECT CS.Extension, SUM(CA.Duration) [Total Talk Time], COUNT(CS.UniqueCallID) [Total Calls], SUM(CASE CS.Answered WHEN '0' THEN SELECT 1 ELSE SELECT 0 END CASE) [Missed Calls]
FROM callSession CS
INNER JOIN callSum CA ON CA.UniqueCallID = CS.UniqueCallID
GROUP BY CS.Extension

Joins are coming back with no rows selected

i'm having some trouble with trying to extract some data from several MySQL tables in a join statement.
My tables and attributes are:
appointment_end_time (table)
appointment_end_time_id (int)(pk)(ai)
appointment_end_date (datetime)
appointment_start_time (table)
appointment_date_id (int)(pk)(ai)
appointment_start_date (datetime)
instructor(table)
instructor_id (int)(pk)(ai)
firstname varchar(45)
lastname varchar(45)
appointment_timetable
appointment_timetable_id int(11) AI PK
instructor_id int(11) FK
appointment_date_id int(11) FK
appointment_end_time_id int(11) FK
SELECT a.appointment_timetable_id, i.instructor_id, ad.appointment_start_date, aet.appointment_end_date
FROM db12405956.appointment_timetable a
JOIN instructor i on i.instructor_id = a.instructor_id
JOIN appointment_start_time ad on ad.appointment_date_id = a.appointment_date_id
JOIN appointment_end_time aet on aet.appointment_end_time_id = a.appointment_end_time_id
ORDER BY a.appointment_timetable_id;
However, this code brings back no rows selected when executed so i'm wondering what i'm doing wrong, any help will be much appreciated
Sample rows:
(appointment_end_time)
appointment_end_time_id appointment_end_date
1 2016-12-26 14:00:00
2 2016-12-24 13:00:00
3 2016-12-26 13:00:00
(appointment_start_time)
appointment_date_id appointment_start_date
1 2016-12-26 15:00:00
2 2016-12-24 16:00:00
3 2016-12-26 15:30:00
instructor_id firstname lastname
1 Sasha Thompson
2 Laura Robinson
3 John Walters
appointment_timetable
appointment_timetable_id instructor_id appointment_date_id appointment_end_time_
1 Blank Blank Blank
2 Blank Blank Blank
3 Blank Blank Blank
What you need is to learn how to diagnose the problem yourself. It is a common problem that a query doesn't return the expected results and you should understand how to break things down to find the issue.
Let's start with your query:
SELECT a.appointment_timetable_id, i.instructor_id, ad.appointment_start_date, aet.appointment_end_date
FROM db12405956.appointment_timetable a
JOIN instructor i on i.instructor_id = a.instructor_id
JOIN appointment_start_time ad on ad.appointment_date_id = a.appointment_date_id
JOIN appointment_end_time aet on aet.appointment_end_time_id = a.appointment_end_time_id
ORDER BY a.appointment_timetable_id;
What you do to break it down is start with the first table and then add the joins (and where conditions although you don't have any here), one at a time until the data problem appears. I find this easiest to do by using select * or select top 1 * (Or top 10 as I usually prefer to see more than one record) instead of the field list because then you don't have to look for the fields that are associated with joins you haven't added in yet.
So start with
SELECT top 10 *
FROM db12405956.appointment_timetable a
Then try
SELECT top 10 *
FROM db12405956.appointment_timetable a
JOIN instructor i on i.instructor_id = a.instructor_id
Then
SELECT top 10 *
FROM db12405956.appointment_timetable a
JOIN instructor i on i.instructor_id = a.instructor_id
JOIN appointment_start_time ad on ad.appointment_date_id = a.appointment_date_id
Finally
SELECT top 10 *
FROM db12405956.appointment_timetable a
JOIN instructor i on i.instructor_id = a.instructor_id
JOIN appointment_start_time ad on ad.appointment_date_id = a.appointment_date_id
JOIN appointment_end_time aet on aet.appointment_end_time_id = a.appointment_end_time_id
ORDER BY a.appointment_timetable_id;
At some point you will see where the records fell out and that is the location of the problem. Then you might need to look at the fields you are joining on and the data in them in your data sets to see why they are not returning any matches. For instance, if you are joining on dates, they may be stored as dates in one table and as varchar in another and date "01/01/2016' is not equal to 'Jan 1, 2016' or sometimes the column has some sort of prefix or suffix not in the other table. Something like PR2345 in one table and 2345 in the other. Sometimes the query is correct and no rows genuinely meet the conditions. This could be because the data is not fully populated yet (think writing a report for a system that is not live yet, no data on completed actions because none have completed yet.) or because the requirement was wrong in some of its assumptions or because there should be no matching records. It could even be a bug in the data entry.
Depending on the nature of the problem, you might need to return all the records or only use select top 1 (since all records are disappearing). Using SELECT * this way will help when you are returning too many or duplicate records as well as sometimes is is the fields not being returning that affect the results set. Note that I am not saying to use SELECT * in your final result set, it is only being used as a diagnostic tool here.
In your case, the problem looks as if it is in the first table. There are blanks for instructor ID and the other fields in your sample, so there is nothing to join on. (You only gave a sample so the rest of the table may not be like this.) If this is a case where the data is not there yet due to the feature that would add it not yet being live, then you can test your query only by adding test data to the table. Be sure to delete this data after you have finished unit testing. If the data should have been there, then you need to look at the insert from the application for a bug.

MySQL Query which require multiple joins

I have a system that is used to log kids' their behavior. If a child is naughty it is logged as negative and if it has a well behaviour it is logged as positive.
For instance - if a child is rude it gets a 'Rude' negative and this is logged in the system with minus x points.
My structure can be seen in this sqlfiddle - http://sqlfiddle.com/#!9/46904
In the users_rewards_logged table, the reward_id column is a foreign key linked to either the deductions OR achievements table depending on the type of column.
If type is 1 is a deduction reward, if the type value is 2 is a achievement reward.
I basically want a query to list out something like this:
+------------------------------+
| reward | points | count |
+------------------------------+
| Good Work | 100 | 1 |
| Rude | -50 | 2 |
+------------------------------+
So it tallys up the figures and matches the reward depending on type (1 is a deduction, 2 is a achievement)
What is a good way to do this, based on the sqlfiddle?
Here's a query that gets the above desired results:
SELECT COALESCE(ua.name, ud.name) AS reward,
SUM(url.points) AS points, COUNT(url.logged_id) AS count
FROM users_rewards_logged url
LEFT JOIN users_deductions ud
ON ud.deduction_id = url.reward_id
AND url.type = 1
LEFT JOIN users_achievements ua
ON ua.achievement_id = url.reward_id
AND url.type = 2
GROUP BY url.reward_id, url.type
Your SQLFiddle had the order of points and type in the wrong order for the table users_rewards_logged.
Here's the fixed SQLFiddle with the result:
reward points count
Good Work 100 1
Rude -50 2
Although eggyal is correct--this is rather bad design for your data--what you ask can be done, but requires a UNION clause:
SELECT users_achievements.name, users_rewards_logged.points, COUNT(*)
FROM users_rewards_logged
INNER JOIN users_achievements ON users_achievements.achievement_id = users_rewards_logged.reward_id
WHERE users_rewards_logged.type = 2
UNION
SELECT users_deductions.name, users_rewards_logged.points, COUNT(*)
FROM users_rewards_logged
INNER JOIN users_deductions ON users_deductions.deduction_id = users_rewards_logged.reward_id
WHERE users_rewards_logged.type = 1
GROUP BY 1, 2
There's no reason NOT to combine the achievements and deductions tables and just use non-conflicting codes. If you combined the tables, then you would no longer need the UNION clause--your query would be MUCH simpler.
I noticed that you have two tables (users_deductions and users_achievements) that defines the type of reward. As #eggyal stated, you are violating the principle of orthogonal design, which causes the lack of normalization of your schema.
So, I have combined the tables users_deductions and users_achievements in one table called reward_type.
The result is in this fiddle: http://sqlfiddle.com/#!9/813d5/6

one to many relationship with many columns

I am VERY new to SQL and do not know that much about it, but I am a quick learner. I have a database with Item IDs and Quantities on Hand (qoh) along with some other columns that I am not having issues with. The problem is that when I tell it to give me the item id column with the qoh column, it gives me almost 500 rows for each individual item because the qoh is different so I literally have about 12 million rows. Now, what I am looking for is the most recent quantity for each item. I am assuming that this is a one-to-many relationship and since I am below a noobie to SQL, I don't even really know where to begin. This is what I have so far:
SELECT DISTINCT item_id, qty_on_hand
FROM database.inv_mast, database.inv_loc
ORDER BY item_id ASC
Oh and I'm using Microsoft SQL Server Management Studio
Here is what I want:
| item_id |qty_on_hand|
|123456789| 93 |
|456789123| 87 |
|789456123| 74 |
etc.
But what I'm getting is:
| item_id |qty_on_hand|
|123456789| 85 |
|123456789| 82 |
|123456789| 92 |
etc.
I am getting the same item_id at least 4000 times because the database is telling me what the qoh was for literally every second of time since we've had the item. I only want what is in the warehouse at the time of me running the query. I apologize for all the noobness, but I literally don't know SQL.
You are doing a cross join by just using ",". What you need to do is a inner join I think.
SELECT DISTINCT im.item_id, qty_on_hand
FROM database.inv_mast im
INNER JOIN database.inv_loc in on im.item_id = in.item_id
ORDER BY item_id ASC
You also should look at left and right joins.
So in summary using "," is like using a cross join
You really need to learn joins to understand these queries, check out the site below.
http://www.w3schools.com/sql/sql_join.asp
The from clause FROM database.inv_mast, database.inv_loc creates the cartesian product. Narrow that down using a WHERE condition.