5 Tables -> Displaying Certain Distinct Rows - mysql

I'm pulling information that will eventually be from 5 tables at once based off of a filtering system. Right now I have three different databases running, its looking great. My issue is I have certain fields that I only want to display distinct information on and others i want to display all. To better explain I'm going to give my example.
My select code:
SELECT w.event,
w.city,
w.DATE,
a.TIME,
w.tmc,
a.weather,
a.surface_temperature,
p.top,
p.LEFT
FROM weather w
LEFT OUTER JOIN application a
ON a.DATE = w.DATE
AND a.tmc = w.tmc
LEFT OUTER JOIN pinlocations p
ON w.city = p.cityname
WHERE w.DATE = '" & datepicker_value.Text & "'
AND w.TIME LIKE '" & eventTime.SelectedItem.Value & "'
I have a map which I'm placing pins on based of the p.top and p.left. When I click on this I want to display the city name, the tmc, and then under that all the other information based off the filtered search. In the example above it creates pins on top of pins, making a new one for each field, I want it to be distinct.
I know the distinct command exists, just not sure how to use it in this situation.
Thanks!

Use a group by modifier, on the values you want to be distinct.
Then use a group_concat on the values you want to have listed in a comma-separated list.
SELECT group_concat(w.event) as events,
group_concat(w.city) as cities,
group_concat(w.`DATE`) as dates,
group_concat(a.`TIME`) as times,
group_concat(w.tmc) as tmcs,
group_concat(a.weather) as weathers,
group_concat(a.surface_temperature) as temperatures,
p.top,
p.LEFT
FROM weather w
LEFT OUTER JOIN application a
ON a.DATE = w.DATE
AND a.tmc = w.tmc
LEFT OUTER JOIN pinlocations p
ON w.city = p.cityname
WHERE w.DATE = '" & datepicker_value.Text & "'
AND w.TIME LIKE '" & eventTime.SelectedItem.Value & "'
GROUP BY p.top, p.left
If a left-top coordinate only ever links to one city (as you'd expect), there's no need to put it inside a group_concat statement. Nor does MySQL require* you to put it in the group by clause.
See:
http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat
* ) you can force MySQL do enforce strict group by rules, but by default it is off.
You cannot use distinct here, because distinct is an all or nothing affair, it operates in the collectivity of all selected values, not just on one field.

Related

SELECT FROM 2 different tables using INNER JOIN

Last time I was able to combined 3 different SELECT queries since it was from the same table. Now, I'm trying to execute a query where in the info was from 2 different tables.
Here's my query string
SELECT applicantinfo.FirstName,
applicantinfo.MiddleName,
applicantinfo.LastName,
applicantaccess.ApplicantExamPassword
FROM applicantinfo
LEFT JOIN applicantaccess WHERE applicantaccess.ApplicantID = '" & lblID.Text & "'"
using myphpadmin to test this query and replacing the lblID.text with a value, Instead of showing up a singe result, it shows 2 rows.
Here's what it looks like
I think I miss used using the INNER JOIN keyword here.
My expected output should only be the first row.
*note
Jaranilla's ID should be '201458971' and password is 6zo93ie82m
lopez's ID should be '201437095' and password is 4ew93fo86t
You have to specify which properties constitute the join, assuming that "id" is the common attribute, e.g.
SELECT applicantinfo.FirstName, applicantaccess.ApplicantExamPassword FROM applicantinfo LEFT JOIN applicantaccess ON applicantinfo.id = applicantaccess.id;
In join put condition on which you want to join both tables, try following appID is you primary key and fk_appID is foregin key.
SELECT applicantinfo.FirstName, applicantinfo.MiddleName, applicantinfo.LastName, applicantaccess.ApplicantExamPassword
FROM applicantinfo as ainfo
LEFT JOIN applicantaccess as aa on ainfo.appID = aa.fk_appID
WHERE applicantaccess.ApplicantID = '" & lblID.Text & "'"

How do you format dates within MS Access Queries to prevent the US/UK issue

How do I ensure that I pick up the right number of records when filtering for dates within an Access Query:
SELECT ID, REF, SalesDate, DCount("ID","tblRecords"," Ref='" & [Ref] & "' AND [SalesDate]=#" & format([SalesDate],"yyyy/mm/dd") & "#") as EXPR1 from tblCurrent
It picks up the date ok if it cannot be misconstrued such as 28-04-12, but if it is 04-06-12 it doesn't pick it up as it's assuming it's the wrong way around.
Note that this query is not created on the fly or generated from a form etc...
I either use yyyy/mm/dd for dates in VBA:
#" & Format([SalesDate],"yyyy/mm/dd") & "#"
Or parameters, for building queries.
EDIT re additional information
Seeing you are using SQL server, I suggest you use a derived table, which you may find faster, for example:
SELECT dbo_Table_1.ADate, ACount FROM dbo_Table_1
LEFT JOIN (SELECT a.ADate,Count(*) As ACount
FROM dbo_Table_1 As a GROUP BY a.ADate) b
ON dbo_Table_1.Adate=b.ADate
EDIT re discussion
SELECT * FROM dbo_vwRecordsCurrent As t
LEFT JOIN (
SELECT a.OpptyIncentiveModifiedDate, a.DataSetID, Count(*) AS ACount
FROM dbo_vwRecordsHistorical AS a
WHERE a.OpportunityIgnored = True
GROUP BY a.OpptyIncentiveModifiedDate, a.DataSetID) AS h
ON t.OpptyIncentiveModifiedDate = h.OpptyIncentiveModifiedDate
AND t.DataSetID = h.DataSetID
I have aliased your tables as the names are very long, so to me, it is more readable to use aliases on the outer sql. They are essential in the inner sql. It is not a good idea to alias a derived table with the name of an existing table.

Subquery without where-clause

Here's my code
SELECT res.type,
res.contactname,
res.id,
res.inv_addressline2,
res.inv_addressline3,
res.signup_date,
res.engineer_id_global,
res.job_id_global,
res.neg_or_pos,
res.rating,
res.author_id_global,
res.timestamp_global,
res.short_description,
res.job_title,
res.feedback,
author_data.contactname AS `author_name`,
review_count.total_feedback,
review_count.total_rating
FROM (SELECT mb.type,
mb.contactname,
mb.id,
mb.inv_addressline2,
mb.inv_addressline3,
mb.signup_date,
fb.engineer_id AS `engineer_id_global`,
fb.timestamp AS `timestamp_global`,
fb.job_id AS `job_id_global`,
fb.neg_or_pos,
fb.rating,
fb.feedback,
fb.author_id AS `author_id_global`,
ac.engineer_id,
ac.timestamp,
ac.author_id,
jb.job_id,
SUBSTR(jb.job_description, 1, 200) AS `short_description`,
jb.job_title
FROM " . MEMBERS_TABLE . " AS mb
LEFT JOIN " . ACCEPTED . " AS ac
ON mb.id = ac.engineer_id
LEFT JOIN " . FEEDBACK . " AS fb
ON ac.job_id = fb.job_id
LEFT JOIN " . JOBS . " AS jb
ON fb.job_id = jb.job_id
WHERE mb.type = 2
ORDER BY
fb.timestamp DESC
) AS res
LEFT JOIN
(SELECT mb.id,
mb.contactname,
fb.author_id
FROM " . MEMBERS_TABLE . " AS mb
LEFT JOIN " . FEEDBACK . " AS fb
ON fb.author_id = mb.id
LIMIT 1
) AS `author_data`
ON res.author_id_global = author_data.author_id
LEFT JOIN
(SELECT COUNT(fb.engineer_id) AS `total_feedback`,
SUM(fb.rating) AS `total_rating`,
fb.engineer_id
FROM " . FEEDBACK . " AS fb
) AS `review_count`
ON res.engineer_id_global = review_count.engineer_id
GROUP BY res.contactname
ORDER BY res.contactname
I'm just starting to get my head around SQL. My worry is the second and third inner query. Am I right in saying it will return all results as there is no where clause and the return the results from that using the "ON" statement or is the "ON" statement combined with the initial query?
There are a number of issues with this script:
You have a number of tables with names like " . MEMBERS_TABLE . ", " . ACCEPTED . " and so on. These are unlikely to be acceptable in MySQL, which normally uses backticks (`) to quote object names; if this script is to be preprocessed by eg. Perl or Python, or is part of a larger script in another language, it would be helpful to say so.
You have an order by clause, for no apparent reason, in your first sub-query. This could be removed.
Your second sub-query links FEEDBACK to MEMBERS_TABLE and limits the results to 1, without specifying the author_id inside the sub-query - this means that a single, random member will be selected inside the sub-query, then linked to the rest of the dataset on the specific author ID, which won't match for most of the rest of the dataset.
The FEEDBACK table is completely irrelevant here, and can be removed.
If id uniquely identifies a record on MEMBERS_TABLE, the sub-query can be completely removed and replaced with a single left join to MEMBERS_TABLE on res.author_id_global = MEMBERS_TABLE.id. No limit clause would be required.
If id does not uniquely identify a record on MEMBERS_TABLE, the sub-query should be rewritten as select distinct id, contact_name FROM " . MEMBERS_TABLE . " AS mb where res.author_id_global = mb.id LIMIT 1. If there are multiple matching authors for the same id, one would be selected at random.
The third sub-query does not require a where clause - it will summarise all engineers' feedback and ratings by engineer within the sub-query, and each engineer will then be linked to the corresponding engineer from the rest of the dataset by the on condition from the left join clause.
Second inner query is having limit 1. It is nothing but where condition to show only one result. Third inner query is not having any problem.

Row counting a JOINed column without affecting the returned rows?

It's a bit difficult getting my problem into a short form, so I apologise if the title doesn't make sense.
Anyway, here is the problem:
$query = '
SELECT issues.*, comments.author AS commentauthor, favorites.userid AS favorited FROM issues
LEFT JOIN comments ON comments.issue = issues.id AND comments.when_posted = issues.when_updated
LEFT JOIN favorites ON favorites.ticketid = issues.id AND favorites.userid = \'' . $_SESSION['uid'] . '\'
' . $whereclause . '
ORDER BY issues.when_updated ' . $order;
Don't mind the fact that it's PHP as I am not asking for PHP help.
The query retrieves a bunch of issues, and what I'm wishing to do is obtain the row count of favorites that have favorites.ticketid matching issues.id. My use of LEFT JOIN favorites is not to get what I've just mentioned, but instead to obtain whether the client has favourited the issue, thus the part favorites.userid AS favorited.
I have tried doing the following: (all at once, I'm putting this in bulleted form for readibility)
duplicating the existing LEFT JOIN favorites and removing the user id check from the duplicate
adding , COUNT(favorites.ticketid) AS favoritescount to the SELECT section
adding AS favorited to the original LEFT JOIN as well as changing favorites.userid to favorited.userid
With that attempt, my query ends up returning only one row.
SELECT issues.*,
comments.author AS commentauthor,
favorites.userid AS favorited,
(
SELECT COUNT(favorites.id)
FROM favorites
WHERE ticketid = issues.id
) AS numfavorites
FROM issues
LEFT JOIN comments
ON comments.issue = issues.id
AND comments.when_posted = issues.when_updated
LEFT JOIN favorites
ON favorites.ticketid = issues.id
AND favorites.userid = ?uid
That should work, I'm just using a subquery to get number of favourites

How to join 1 table twice in the same query and keep results separate

we're building a scheduler system and have a couple of situations where we're trying to get some notes from a table to display. We've looked at other answers and none seem to quite match this problem.
The bookings table holds a numeric reference to both a client note (if present) and a stylist note (if present).
The notes table holds both client and stylist notes, each indexed by a unique numeric index
We've got our query working when we just want to read in the client notes:
SELECT bookings.bookingID, UNIX_TIMESTAMP(bookings.startDate) AS start_date, UNIX_TIMESTAMP(bookings.endDate) as end_date, clientDetails.firstName, clientDetails.lastName, clientDetails.phone1, clientDetails.phone2, clientDetails.email, services.name, services.serviceID, cNotes.note as client_notes, sNotes.note as stylist_note
FROM bookings
LEFT JOIN clientDetails ON bookings.clientID = clientDetails.clientID
LEFT JOIN services ON bookings.serviceID = services.serviceID
LEFT JOIN notes ON bookings.clientNotes = notes.notesID
WHERE bookings.startDate >= '" . $start_date . "' AND bookings.endDate <= '" . $end_date . "' AND bookings.stylistID = '" . $stylist_id . "'
ORDER BY bookings.startDate ASC;
Using this logic we can access the cient notes from the results array in php simply as: $results_array['note']
What we also want to be able to do is to get the stylist note for that booking as well, something like $results_array['stylist_note'].
How can we join the notes table again this time using:
LEFT JOIN notes ON bookings.stylistNotes = notes.notesID
BUT be able to reference these stylist notes separately from the client notes.
Thanks so much for any assistance.
You should be able to alias the table and columns:
SELECT ..., stylistnotes.note AS stylist_note
FROM ...
LEFT JOIN notes stylistnotes ON bookings.stylistNotes = stylistnotes.notesID