Subquery without where-clause - mysql

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.

Related

Pull result for missing data

How to match and product_id in the query
atm the query is pull only missing result but each product have his own record and need to match with this record
This query work right but isn't match product_id
SELECT oc_ekstri_frontend.*,
oc_ekstri_image.id as img_id,
oc_ekstri_image.name
FROM oc_ekstri_image
LEFT JOIN oc_ekstri_frontend ON (oc_ekstri_frontend.id = oc_ekstri_image.frontend_id)
LEFT JOIN oc_ekstri_frontend_view ON (oc_ekstri_frontend_view.ekstri_id = oc_ekstri_image.id)
WHERE oc_ekstri_frontend.subcat_id = '" . $id . "'
AND oc_ekstri_frontend_view.ekstri_id IS NULL
How will I match for current product_id?
I tried something like this to add to the query but isn't work result is empty
AND oc_ekstri_frontend_view.product_id = '" . $product_id . "'
Without seeing your data or your expected output, it is hard to give an exact answer. One possible solution might be to move your new restriction from the WHERE clause to the ON clause:
SELECT
f.*,
i.id AS img_id,
i.name
FROM oc_ekstri_image i
LEFT JOIN oc_ekstri_frontend f
ON f.id = i.frontend_id
LEFT JOIN oc_ekstri_frontend_view v
ON v.ekstri_id = i.id AND
v.product_id = ?
WHERE
f.subcat_id = ? AND
v.ekstri_id IS NULL;
I use ? placeholders in the above query to suggest that you use a prepared statement rather than concatenating in your parameters. If you don't know what prepared statements are in PHP, you should read about them.

Database query taking forever to load

I have a query that I'm trying to create but it takes forever for the page to load when the query is active...
What I'm trying to do is:
I have a video website, and when you click on a video, you are redirected to the VIDEO page where you can see the video and the url structure is like this:
www.site.com/VIDEO_CATEGORY_NAME/VIDEO_ID.html
The video_category and video_id are in separate tables.
What I'm trying to achieve is: make a link so when user clicks it will get redirected to a RANDOM video page (random video).
Here is the query I'm trying to write:
$db = JFactory::getDBO();
$query = "SELECT distinct a.*,b.category FROM #__hdflv_upload a LEFT JOIN #__hdflv_category b on a.playlistid=b.id or a.playlistid=b.parent_id WHERE a.published='1' and b.published='1' and b.id=" . $videocategory1 . " and a.id != " .$videoid1 ." order by rand()";
$db->setQuery($query);
$result = $db->loadResult();
and the link:
random video
When the query is on the page it takes forever to load the page...
Can somebody give me a hand please. Thank you
To avoid the OR in the ON clause of the join, try using a UNION instead.
SELECT a.*, b.category
FROM #__hdflv_upload a
INNER JOIN #__hdflv_category b
ON a.playlistid=b.id
WHERE a.published='1' AND b.published='1'
AND b.id=" . $videocategory1 . "
AND a.id != " .$videoid1 ."
UNION
SELECT a.*, b.category
FROM #__hdflv_upload a
INNER JOIN #__hdflv_category b
ON a.playlistid=b.parent_id
WHERE a.published='1' AND b.published='1'
AND b.id=" . $videocategory1 . "
AND a.id != " .$videoid1 ."
ORDER BY RAND()
The UNION also removes duplicate records, so rendering the DISTINCT irrelevant.
Note that ORDER BY RAND() can be pretty inefficient. There are more efficient solutions but advising on that would require knowing more about your data (eg, table declares, if id fields are contiguous, etc).

5 Tables -> Displaying Certain Distinct Rows

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.

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