I want to know the difference between below queries. Both returns the same value. I have idea about INNER JOIN and but i can't understand how first query returns the same value.
SELECT *
FROM
`products`
WHERE
(
SELECT count(*)
FROM `categories`
WHERE `products`.`category_id` = `categories`.`id` AND `slug` = 'aprons'
) >= 1
AND `slug` <> 'products-1'
SELECT products.*
FROM
products
INNER JOIN categories ON categories.id = products.category_id
WHERE
products.slug <> 'products-1'
AND categories.slug = 'aprons'
the second query is more efficient. and have use inner join . first one is used a sub query. sub query is not necessary to verify to categories existence. same result are displayed but on point of optimisation second query is more efficient.
when thinking the first query
(
SELECT count(*)
FROM categories
WHERE products.category_id = categories.id AND slug = 'aprons'
) >= 1
this part is execute for every single products record . simply categories is iterated for every single record in products table.
The first query will be more efficient since the tables will not need to be joined. You may not have noticed a big difference in execution time, but if the tables were much larger, you would have noticed that the first query returned much faster.
An Inner Join will combine the two tables based on the rows that have values in both tables. In other words, there will not be any null values in the resulting table.
Related
I have the following query in my application:
SELECT
p.old_product_id,
l.product_id,
p.sku,
p.title,
p.option_one,
p.option_two,
FROM
lookup_id l
JOIN temp_price_tables_data p USING (sku);
And it works great. However, a small percentage of records from the temp_price_tables_data tables don't make it to the results.
This is because the skus from the lookup_id table don't exist in the temp_price_tables_data.
Is there a way to keep these records in the new data?
Or is there a way to only get those records so I can store the result for later processing?
EDIT:
First table columns = old_product_id, sku, title, option_one, option_two
Second table column = product_id, sku
Tables should have SKU in common.
Use a left outer join:
SELECT
*
FROM
lookup_id l
LEFT OUTER JOIN price_tables_data p on l.sku = p.sku
WHERE old_product_id IS NULL;
That will get you all the records that are in temp_price_tables_data but not in lookup_id
My SQL query doesn't return an output that suppose to be specified by my where clause.
Here is my query:
SELECT
transaction_details.transaction_id
,transaction_details.transaction_number
,transaction_details.product_id
,Products3.ProductName
FROM transaction_details
INNER JOIN Products3
ON transaction_details.product_id = Products3.productID
INNER JOIN transaction_status
ON transaction_details.transaction_id = transaction_status.transaction_id
WHERE status_of_transaction = 'review'
This query should return me table rows with a status_of_transaction = 'review'.
Here is my table which contains the status_of_transaction
I tried DISTINCT but its not working.
and this is the output I always get:
is there something wrong with my query its is returning table row which was not specified by my WHERE clause?
There are multiple rows generated by the set (remember this is all set theory) - you are missing a Foreign Key/Primary Key (FK/PK) relationship in the JOIN. I'll bet you missed a column in the INNER JOIN "ON" statement. There are probably two columns necessary to JOIN on to find the proper solution.
I suggest either picking it apart table by table, or using select * and look for the difference in the column values between each row. One column should be different - which you currently cannot see (i.e. hidden) because the column is not in the current SELECT statement.
Try this...
SELECT
transaction_status.*
FROM transaction_details
INNER JOIN Products3
ON transaction_details.product_id = Products3.productID
INNER JOIN transaction_status
ON transaction_details.transaction_id = transaction_status.transaction_id
WHERE status_of_transaction = 'review'
I believe the issue is with the transaction_status join. The transaction_id is the same for both rows in transaction_details - which matches TWO rows in transaction_status. SQL will create 4 rows -- two rows that match "review" and two rows for "replied" (remove the WHERE to see them). This is a cross join of sorts.
Does the _status table also contain transaction_number? There needs to be a way to JOIN to the single row in transaction_details to a single row in transaction_status. Somehow that _status row belongs to the _details row. Look at (or ask the DBA) the PK/FK definitions for both tables.
Not knowing your schema - I would guess the solution is....
SELECT
transaction_details.transaction_id
,transaction_details.transaction_number
,transaction_details.product_id
,Products3.ProductName
FROM transaction_details
INNER JOIN Products3
ON transaction_details.product_id = Products3.productID
INNER JOIN transaction_status
ON transaction_details.transaction_id = transaction_status.transaction_id
-- ADDED NEXT LINE
AND transaction_details.transaction_number = transaction_status.transaction_number
-- END Change
WHERE status_of_transaction = 'review'
Most likely one of the inner joins is matching more than one row, so it generates two rows in the output set. Run the query with:
select transaction_details.transaction_id
, Products3.product_id
, transaction_details.detail_id
to examine which join is the culprit.
I have this statement:
SELECT board.*, numlikes
FROM board
LEFT JOIN (SELECT
pins.board_id, COUNT(source_user_id) AS numlikes
FROM likes
INNER JOIN pins ON pins.id = likes.pin_id
GROUP BY pins.board_id) likes ON board.id = likes.board_id
WHERE who_can_tag = ''
ORDER BY numlikes DESC LIMIT 10
But I need to also join these other two statements to it:
SELECT COUNT(owner_user_id)
FROM repin
INNER JOIN pins ON pins.id = repin.from_pin_id
WHERE pins.board_id = '$id'
and
SELECT COUNT(is_following_board_id)
FROM follow
WHERE is_following_board_id = '$id'
I managed to get the first one joined but I'm having trouble with the others - thinking it might get too long.
Is there a quicker way to execute?
Ideally, start with the smallest result set, and then start joining to the next smallest table.
You don't want the database to do full table joins on a bunch of big tables, and then at the end have a where clause that removes 99% of the rows the database just created.
In Oracle, I do a:
SELECT *
FROM big_table bt
JOIN DUAL ON bt.best_filter_column='the_value'
--now there are only a few rows
JOIN other_table_1 ...
LEFT JOIN outer_join_tables ...
Include all OUTER JOINS last, since they don't drop any rows, so hopefully you've already filtered out a lot of rows.
Given the following query…
SELECT DISTINCT *
FROM PAS_Post
WHERE post_user_id = 21
GROUP BY post_post_id
UNION
SELECT DISTINCT PAS_Post.*
FROM PAS_Follow LEFT JOIN PAS_Post ON (
PAS_Follow.folw_followed_user_id = PAS_Post.post_user_id
)
WHERE PAS_Follow.folw_follower_user_id = 21
GROUP BY post_post_id
ORDER BY post_posted_date DESC
I always get a row in the results that is just NULL's, unfortunately I need to preserve some NULL values in the data as the Post's table (PAS_Post) holds different types of information.
Can anyone steer me in the right direction to get rid of this null row.
I do not want or need the last row here
You're using a (left) outer join in the second part of the UNION, so any cases that do not satisfy the join criteria will result in data from the table on the left of the join (PAS_Follow), but NULL in every column of the table on the right of the join (PAS_Post); the subsequent selection only of columns from the latter table results in the NULL rows that you observe. Therefore, the simplest solution is to use an inner join (that completely excludes records where the join criteria is not met).
However, in your case, it appears that your query can be greatly simplified by simply using two possible conditions in a filter on the joined tables rather than a UNION:
SELECT p.*
FROM PAS_Post AS p
JOIN PAS_Follow AS f ON f.folw_followed_user_id = p.post_user_id
WHERE p.post_user_id = 21
OR f.folw_follower_user_id = 21
ORDER BY p.post_posted_date DESC
I have excluded the GROUP BY clause on the assumption that post_post_id is the primary key (or at very least is UNIQUE) in your PAS_Post table. If that assumption is incorrect, you may want to reintroduce it—but beware that MySQL will indeterminately select the values that will be returned from each group.
I've got a serious problem with a nested query, which I suspect MySQL is interpreting as a correlated subquery when in fact it should be uncorrelated. The query spans two tables, one being a list of products and the other being their price at various points in time. My aim is to return each price record for products that have a price range above a certain value for the whole time. My query looks like this:
SELECT oP.id, oP.title, oCR.price, oC.timestamp
FROM Crawl_Results AS oCR
JOIN Products AS oP
ON oCR.product = oP.id
JOIN Crawls AS oC
ON oCR.crawl = oC.id
WHERE oP.id
IN (
SELECT iP.id
FROM Products AS iP
JOIN Crawl_Results AS iCR
ON iP.id = iCR.product
WHERE iP.category =2
GROUP BY iP.id
HAVING (
MAX( iCR.price ) - MIN( iCR.price )
) >1
)
ORDER BY oP.id ASC
Taken alone, the inner query executes fine and returns a list of the id's of the products with a price range above the criterion. The outer query also works fine if I provide a simple list of ids in the IN clause. When I run them together however, the query takes ~3min to return ~1500 rows, so I think it's executing the inner query for every row of the outer, which is not ideal. I did have the columns aliased the same in the inner and outer queries, so I thought that aliasing them differently in the inner and outer as above would fix it, but it didn't.
Any ideas as to what's going on here?
MySQL might think it could use indexes to execute the query faster by running it once for every OP.id. The first thing to check is if your statistics are up to date.
You could rewrite the where ... in as a filtering inner join. This is less likely to be "optimized" for seeks:
SELECT *
FROM Crawl_Results AS oCR
JOIN Products AS oP
ON oCR.product = oP.id
JOIN Crawls AS oC
ON oCR.crawl = oC.id
JOIN (
SELECT iP.id
FROM Products AS iP
JOIN Crawl_Results AS iCR
ON iP.id = iCR.product
WHERE iP.category =2
GROUP BY
iP.id
HAVING (MAX(iCR.price) - MIN(iCR.price)) > 1
) filter
ON OP.id = filter.id
Another option is to use a temporary table. You store the result of the subquery in a temporary table and join on that. That really forces MySQL not to execute the subquery as a correlated query.