MySQL Left Join not showing rows from other table - mysql

I have 2 tables. 1 table shows location information, and another shows wifi ssids and passwords for the location. These tables are joined by a column 'LocationID'. The reason for the 2 separate tables is so that I can keep a historical trail of ssids and passwords for a specific location.
My query is as follows:
SELECT Location.LocationID,
Location.SystemName,
Location.SiteNameLocation,
Location.SiteAddress1,
Location.SiteAddress2,
Location.SiteCity,
Location.SiteProvince,
Location.SitePostalCode,
Location.ContactName,
Location.ContactPhone,
Location.ContactEmail,
Location.ID1POC,
Location.ID2District,
Location.SiteLocationHours,
LocationWiFi.WiFiSSID,
LocationWiFi.WiFiPassphrase,
LocationWiFi.WiFiDate
FROM Location
LEFT JOIN LocationWiFi ON LocationWiFi.LocationID = Location.LocationID
What I need to do is obtain the most recent wifi ssid and passphrase from the table to show it with the corresponding locationID
I can do it with the following query:
SELECT * FROM LocationWiFi WHERE WiFiDate = (SELECT MAX(WiFiDate) FROM LocationWiFi) AND LocationID = xxxx
I am sure it isnt that hard, I just can not quite figure it out. Thanks in advance for any help!
EDIT...
Sorry for the confusion here everyone. let me try and be more clear. I have 1500+ entrys in location table. 2 entries in LocationWiFi table with the same locationid. I need the first query (the one with the join) to return all 1500+ rows, but only pull the wifi ssid and password with the max date. For the locations that do not have wifi ssid and passphrase, i simply want to show the column with a null value.
Again I apologize
SOLUTION
Hi Everyone,
I have solved this issue. For anyone who is having a similar solution, here is what worked for me.
SELECT Location.LocationID,
Location.SystemName,
Location.SiteNameLocation,
Location.SiteAddress1,
Location.SiteAddress2,
Location.SiteCity,
Location.SiteProvince,
Location.SitePostalCode,
Location.ContactName,
Location.ContactPhone,
Location.ContactEmail,
Location.ID1POC,
Location.ID2District,
Location.SiteLocationHours,
a.WiFiSSID,
a.WiFiPassphrase
FROM Location
LEFT JOIN(
SELECT LocationWiFi.WiFiSSID,
LocationWiFi.WiFiPassphrase,
LocationWiFi.LocationID
FROM LocationWiFi
WHERE LocationWiFi.WiFiDate = (SELECT MAX(WiFiDate) FROM LocationWiFi)
) AS a
ON a.LocationID = Location.LocationID;

The following query is more efficient since it is not using a sub query:
SELECT *
FROM LocationWiFi
WHERE LocationID = xxxx
ORDER BY WiFiDate DESC
LIMIT 1

You had everything you needed, just have to put them together:
SELECT l.*, lw.*
FROM Location l
JOIN LocationWifi lw ON l.locationId= lw.locationId
WHERE lw.WiFiDate = (
SELECT MAX(WiFiDate)
FROM locationWifi
WHERE locationId = l.locationId
);
It's subquery per row, but I don't think there is any good way around it.
SQLFiddle: http://sqlfiddle.com/#!2/350ac/1

Related

Inner join in combination with sum and group by

I am having some strange issue with the SQL statement below. The result groups by user IDs and some of them turn out right but for one of them (user ID = 1) the "initial_average" is multiplied by 3. I really have no idea why.. Is there something wrong with the structure of the statement? If it is not clear, the aim is to sum the field "initial_avg" in the "tasks" table and have it broken out by user. Some help with this is much appreciated. I am using MySQL.
SELECT sum(initial_avg) AS initial_average
, sum(initial_std) AS initial_standard_dev
, tasks.user
, hourly_rate
FROM tasks
INNER JOIN user_project
ON tasks.user=user_project.user
AND tasks.project=59
AND tasks.user=1
GROUP BY tasks.user
I just solved it by adding another "and" clause (AND user_project.project=59 )
Optimize your query (Try it):
SELECT SUM(initial_avg) AS initial_average, SUM(initial_std) AS initial_standard_dev, tasks.user, hourly_rate FROM tasks INNER JOIN user_project ON tasks.user = user_project.user AND tasks.project = User_project.project WHERE tasks.project = 59 AND tasks.user = 1 GROUP BY tasks.user, hourly_rate

MYSQL Query - Checking result is true/false and count

I am trying to check if the current user is already following the selected user, and I am doing this like so:
(I know it's not the best way, but as I am new to MYSQL this is as much as I have been able to come up with)
SELECT EXISTS (SELECT 1 FROM Activity WHERE IdOtherUser = 86 AND id = 145)
I am '145' and the user I selected is '86'.
Now that return '0' If I am not following and '1' If I am following that person.
Seems to be working already but it definetly needs improving!
Now what I would like to do is count the followers in the same query.
So count the people I am following and the people following me.
'Activity' is the table where I store the followers and I save them like this:
'id' = me
'idOtherUser' = other user I followed
'type' = type of action "follow"
I have done count's before when calculating the like counts, but I just cannot get my head around this!!
If anyone could spare some time to help me it is much appreciated!
I am sorry if the question is not the best, but I am still learning and trying my best to format them as clear as possible to understand.
Thanks in advance!!
If you trying to count the followers from specific id from table Activity you might do this way:
SELECT COUNT(idOtherUser) AS "I Follow",
(SELECT COUNT(idOtherUser) FROM Activity WHERE idOtherUser = 145 AND type = "follow"
) AS "FOLLOW ME",
(SELECT COALESCE(id,0) FROM Activity WHERE IdOtherUser = 86 AND id = 145 AND type = "follow")
FROM Activity WHERE id = 145 AND type = "follow"
you can use a "correlated subquery" to simplify the query and you might want distinct in the count also (depends on you data). I would avoid using spaces in column aliases too.
SELECT
COUNT(DISTINCT A1.idOtherUser) as i_follow
, (
SELECT
COUNT(DISTINCT A2.id)
FROM Activity A2
WHERE A2.idOtherUser = A1.id
AND A2.type = 'follow'
) as following_me
FROM Activity A1
WHERE A1.id = 145
AND A1.idOtherUser = 86
AND A1.type = 'follow'
Try it with distinct then without, if the result is the same leave distinct out of the query.

Get list of records from mysql database having following conditions:

Firstly i apologize for vague question title, i am not sure what to write there. Please let me know and i will update it.
Now here it goes..
I have 3
Table : target
Columns : target_id , target_employee_id, target_location_id, target_location_name, target_scheduled_on, target_exec_end_time, target_damaged, target_damaged_text
Table : employee
Columns : employee_id, employee_manager_id
Table : location
Columns : location_id, location_name
Little Explaination-> Managers role is to create a target for employee meaning a new target will have the location name and the scheduled on. Then employee will visit that location and report if there are any damages. This can happen multiple times in a month for same location.
What i need to show-> a list of targets having damages - between two dates (target_exec_end_time) and if there are multiple records of that same location then show the one having max date.
More Explaination-> There can be multiple entries of targets having same location but i need to show only one instance. target table image
I have tried my best to explain. Thanks in advance.
How about this:
select * from target join employee on target.target_employee_id = employee.employee_id
join location on target.target_location_name = location.location_name
where target_exec_end_time between <start_date> and <end_date>
and target_exec_end_time = (select max(target_exec_end_time) from location loc2
where loc2.location_name = target.location_name)
group by target.location_name;
Not sure about having both target_exec_end_time clauses in the where though. Maybe you just want the max value?
SELECT MAX(target_exec_end_time), *
FROM target
WHERE target_damaged=1
AND target_exec_end_time BETWEEN '2012-12-01' AND '2012-12-31'
GROUP BY target_location_id
select t.target_location_name,case when t.target_damaged >0
then t.target_damaged_text else 'Not Damaged' end target_damaged_text,
max(t.target_exec_end_time) from target t
inner join employee e on t.target_employee_id=e.employee_id
inner join location l on t.target_location_id=l.location_id
where t.target_exec_end_time between 'DATE1' and 'DATE2'
group by t.target_id,t.target_damaged_text

SQL Query returns fake duplicate results?

I've been trying to write a few little plugins for personal use with WHMCS. Essentially what I'm trying to do here is grab a bunch of information about a certain order(s), and return it as an array in Perl.
The Perl bit I'm fine with, it's the MySQL query I've formed that's giving me stress..
I know it's big and messy, but what I have is:
SELECT tblhosting.id, tblhosting.userid, tblhosting.orderid, tblhosting.packageid, tblhosting.server, tblhosting.domain, tblhosting.username, tblorders.invoiceid, tblproducts.gid, tblservers.ipaddress, tblinvoices.status
FROM tblhosting, tblproducts, tblorders, tblinvoices, tblservers
WHERE tblorders.status = 'Pending'
AND tblproducts.gid = '2'
AND tblservers.id = tblhosting.server
AND tblorders.id = tblhosting.orderid
AND tblinvoices.id = tblorders.invoiceid
AND tblinvoices.status = 'Paid'
I don't know if this /should/ work, but I assume I'm on the right track as it does return what I'm looking for, however it returns everything twice.
For example, I created a new account with the domain 'sunshineee.info', and then in PHPMyAdmin ran the above query.
id userid orderid packageid server domain username invoiceid gid ipaddress status
13 7 17 6 1 sunshineee.info sunshine 293 2 184.22.145.196 Paid
13 7 17 6 1 sunshineee.info sunshine 293 2 184.22.145.196 Paid
Could anyone give me a heads up on where I've gone wrong with this one.. Obvioiusly (maybe not obviously enough) I want this as only one row returned per match.. I've tried it with >1 domain in the database and it returned duplicates for each of the matches..
Any help would be much appreciated
:)
SELECT distinct tblhosting.id, tblhosting.userid, tblhosting.orderid, tblhosting.packageid, tblhosting.server, tblhosting.domain, tblhosting.username, tblorders.invoiceid, tblproducts.gid, tblservers.ipaddress, tblinvoices.status
FROM tblhosting, tblproducts, tblorders, tblinvoices, tblservers
WHERE tblorders.status = 'Pending'
AND tblproducts.gid = '2'
AND tblservers.id = tblhosting.server
AND tblorders.id = tblhosting.orderid
AND tblinvoices.id = tblorders.invoiceid
AND tblinvoices.status = 'Paid'
Well, its near impossible without any table definitions, but you are doing a lot of joins there. You are starting with tblhosting.id and working your way 'up' from there. If any of the connected tables has a double entry, you'll get more hits
You could add a DISTINCT to your query, but that would not fix the underlying issue. It could be a problem with your data: do you have 2 invoices? Maybe you should select everything (SELECT * FROM) and check what is returned, maybe check your tables for double content.
Using DISTINCT is most of the time not a good choice: it means either your query or your data is incorrect (or you don't understand them thoroughly). It might get you the right result for now, but can get you in trouble later.
A guess about the reason this happens:
You do not connect the products table to the chain of id's. So you are basically adding a '2' to your result as far as I can see. You join on products, and the only thing that limits that table is that "gid" should be 2. So if you add a product with gid 2 you get another result. Either join it (maybe tblproduct.orderid = tblorders.id ? just guessing here) or just remove it, as it does nothing as far as I can see.
If you want to make your query a bit clearer, try not implicitly joining, but do it like this. So you can actually see what's happening
SELECT tblhosting.id, tblhosting.userid, tblhosting.orderid, tblhosting.packageid, tblhosting.server, tblhosting.domain, tblhosting.username, tblorders.invoiceid, tblproducts.gid, tblservers.ipaddress, tblinvoices.status
FROM tblhosting
JOIN tblproducts ON /*you're missing something here!*/
JOIN tblorders ON tblorders.id = tblhosting.orderid
JOIN tblinvoices ON tblinvoices.id = tblorders.invoiceid
JOIN tblservers ON tblservers.id = tblhosting.server
WHERE
tblorders.status = 'Pending'
AND tblproducts.gid = '2'
AND tblinvoices.status = 'Paid'
I don't see in your query JOIN to tblproducts, it seems to be a reason.

Can anyone help me with a complex sum, 3 table join mysql query?

Hey guys I have a query and it works fine, but I want to add another table to the mix. The invite table I want to add has two fields: username and user_invite. Much like this site, I am using a point system to encourage diligent users. The current query which is displayed below adds the up votes and down votes based on the user in question: $creator. I want to count the number of entries for that same user from the invite table, and add 50 for each row it finds to the current output/sum of my query. Is this possible with one query, or do I need two?
"SELECT *,
SUM(IF(points_id = \"1\", 1,0))-SUM(IF(points_id = \"2\", 1,0)) AS 'total'
FROM points
LEFT JOIN post ON post.post_id=points.points_id
WHERE post.creator='$creator'"
This should work :
SELECT *,**SUM(IF(points_id = "1", 1,0))-SUM(IF(points_id = "2", 1,0))+(select count(*)*50
from inivite where username='$creator') AS 'total'**,
FROM points LEFT JOIN post ON post.post_id=points.points_id WHERE post.creator='$creator'"
Assuming that there might be no correspondence in invite table, I used outer join and coalesce:
SET #good='1', #bad='2', #creator='$creator';
SELECT *,
SUM(IF(points_id=#good, 1,0))-SUM(IF(points_id=#bad, 1,0))+COALESCE(inv_cnt, 0) * 50) AS total
FROM points
LEFT JOIN post
ON post.post_id=points.points_id
LEFT OUTER JOIN (SELECT username, COUNT(user_invite) as inv_cnt
FROM invite
GROUP BY username) invites
ON post.creator = invites.username
WHERE post.creator=#creator;
Designing this query with limited knowledge of the schema...
SELECT *,
SUM(IF(points_id = \"1\", 1,0))
-SUM(IF(points_id = \"2\", 1,0))
+ 50 * COUNT(invite.user_invite) AS 'total' <--
FROM points
LEFT JOIN post ON post.post_id=points.points_id <--
LEFT JOIN invite ON post.creator = invite.user_invite
WHERE post.creator='$creator'
The important thing here is the extra lines, which I've marked with "<--". One is for JOINing your two tables together, the other is to modify the argument of the SUM function.
Post back if this doesn't work.