I have the following query:
SELECT
usp.user_id AS userId,
usp.create_time AS create_time,
ml.amount AS amount
FROM user_subscription_plan AS usp
RIGHT JOIN product AS product ON product.id = usp.product_id
LEFT JOIN modification_log AS ml ON ml.subscription_id = usp.id
WHERE usp.id IN ('447482')
I have three tables, from which I need to select data.
My problem begins with the last LEFT join.
modification_log table could have no entries, but also it could have more entries.
I want to select only the latest entry. With the above query, if I have 2 (or more) entries in the modification_log, I receive 2 identical results (repeated).
What I would like to get:
If there are no results in the modification_log, then it will return null. I think that is covered with LEFT JOIN. But also, in the case of many record, I would need to select the latest added one (amount)
I believe I might need a sub-query, but I fail to implement it.
You have to use a subquery for taking left join with modification_log table as
SELECT
usp.user_id AS userId,
usp.create_time AS create_time,
ml.amount AS amount
FROM user_subscription_plan AS usp
RIGHT JOIN product AS product ON product.id = usp.product_id
LEFT JOIN
(select * modification_log where subscription_id
IN ('447482') order by created_at desc LIMIT 1)
AS ml ON ml.subscription_id = usp.id
WHERE usp.id IN ('447482')
Note that the where clause in subquery select * modification_log where subscription_id IN ('447482')
is the same as with the last where condition
Just add a max condition after your left join to get the latest entry to be joined, like below-
LEFT JOIN modification_log AS ml ON ml.subscription_id = usp.id
where usp.id IN ('447482') and ml.id = (select max(id) from modification_log)
Related
Iam currently trying to left join a table on a left joined table as follows.
I have the tables:
accounts (id, vorname, nachname)
projektkurse (id, accounts_id, projektwochen_id)
projektkurs_einzel (id, projektkurse_id)
projektkurs_einzel_zeiten (id, date, shift, projektkurs_einzel_id)
Now I want to get every account and the amount times they have an entry inside of projektkurs_einzel_zeiten, which should also be unique. So having the same date and shift multiple times does not count as multiple entries. The result should also be limited by the column projektwochen_id from the table projektkurse. This column should match a certain value for example 8.
Some Accounts don't have any entries in projektkurse, projektkurs_einzel and projektkurs_einzel_zeiten, this is why my first thought was using LEFT JOIN like this:
SELECT accounts.id, accounts.vorname, accounts.nachname, COUNT(DISTINCT projektkurs_einzel_zeiten.date, projektkurs_einzel_zeiten.shift) AS T
FROM accounts
LEFT JOIN projektkurse on accounts.id = projektkurse.creator_id
LEFT JOIN projektkurs_einzel on projektkurse.id = projektkurs_einzel.projektkurs_id
LEFT JOIN projektkurs_einzel_zeiten ON projektkurs_einzel.id = projektkurs_einzel_zeiten.projektkurs_einzel_id
WHERE projektkurse.projektwochen_id = 8
GROUP BY accounts.id
This query does not achieve exactly what I want. It only returns accounts that have atleast one entry in projektkurse even if they have none in projektkurs_einzel and projektkurs_einzel_zeiten. The Count is obviously 0 for them but the accounts that have no entries in projektkurse are being ignored completly.
How can I also show the accounts that don't have entries in any other table with the Count 0 aswell?
I would recommend writing the query like this:
SELECT a.id, a.vorname, a.nachname,
COUNT(DISTINCT pez.date, pez.shift) AS T
FROM accounts a LEFT JOIN
projektkurse
ON a.id = pk.creator_id AND
pk.projektwochen_id = 8 LEFT JOIN
projektkurs_einzel pe
ON pk.id = pe.projektkurs_id LEFT JOIN
projektkurs_einzel_zeiten pez
ON pe.id = pez.projektkurs_einzel_id
GROUP BY a.id, a.vorname, a.nachname;
Notes:
Your problem is fixed by moving the WHERE condition to the ON clause. Your WHERE turns the outer join into an inner join, because NULL values do not match.
Table aliases make the query easier to write and to read.
It is a best practice to include all unaggregated columns in the GROUP BY. However, assuming that id is unique, your formulation is okay (due to something called "functional dependencies").
You should not use eft join table's column ins where condition this work as inner join
You should move the where condition for a left joined table in the corresponding ON clause
SELECT accounts.id, accounts.vorname, accounts.nachname, COUNT(DISTINCT projektkurs_einzel_zeiten.date, projektkurs_einzel_zeiten.shift) AS T
FROM accounts
LEFT JOIN projektkurse on accounts.id = projektkurse.creator_id
AND projektkurse.projektwochen_id = 8
LEFT JOIN projektkurs_einzel on projektkurse.id = projektkurs_einzel.projektkurs_id
LEFT JOIN projektkurs_einzel_zeiten ON projektkurs_einzel.id = projektkurs_einzel_zeiten.projektkurs_einzel_id
GROUP BY accounts.id
These two requirements must be met:
Select products that have the status "waiting".
The last e-mail must have been sent 3 days ago.
The following tables and columns are given:
products: id, name, status_id, notification
status: id, name
emaillogs: id, product_id, subject, text, date_created
I tried the following:
SELECT
product.id
FROM
product
LEFT JOIN
status ON product.status_id = status.id
INNER JOIN
emaillog ON product.id = emaillog.product_id
AND (emaillog.date_created <= '2018-11-04 16:32:49')
WHERE
(status.name = 'waiting' AND product.notification = 1)
GROUP BY emaillog.product_id
This works only if there are records in the emaillogs table. If there are no records in the emaillogs table, the products should nevertheless be selected.
Use LEFT JOIN rather than ordinary inner JOIN if you want to preserve unjoined rows in your result set. But, beware, mentioning a column from a left-joined table in your WHERE clause converts the left join to an inner join.
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
I have SQL like below:
SELECT
p1.*
FROM
payment p1
INNER JOIN (
SELECT
p2.contract_id_fk,
MAX(p2.payment_id_pk) AS maxpay
FROM
payment p2
GROUP BY
p2.contract_id_fk) p2
ON (
p1.payment_id_pk = p2.maxpay)
LEFT JOIN
contracts c
ON (
c.contract_id_pk = p1.contract_id_fk)
WHERE
p1.contract_id_fk != 0
AND
p1.payment_remain=0;
The first join is to get the last record when I use group by
my problem is in the second join. It doesn't get the data from the second table named contracts.
The result is the right record that I need but without the data from the second joined table.
You've only asked for the first table. SELECT p1.* You need to include whatever fields you need from the second table in the select, ie select p1.*, p2.*
I have movie database that has these tables: new_movies, ratings, critic_ratings, colors
I'm trying to execute this SELECT statement which will combine these 4 tables on the same movie using 'mid' (movie id):
SELECT DISTINCT
new_movies.*,
movies_db.*,
ratings.rating,
ratings.count,color,
critic_ratings.rating AS critic_ratings
FROM
new_movies
INNER JOIN
movies_db
ON
new_movies.mid = movies_db.mid
LEFT JOIN
ratings
ON
new_movies.mid = ratings.mid
LEFT JOIN
colors
ON
new_movies.mid = colors.mid
LEFT JOIN
critic_ratings
ON
new_movies.mid = critic_ratings.mid
ORDER BY
title ASC
But I get this error:
The SELECT would examine more than
MAX_JOIN_SIZE rows; check your WHERE
and use SET SQL_BIG_SELECTS=1 or SET
SQL_MAX_JOIN_SIZE=# if the SELECT is
okay
How do I properly do this query?
If you don't want to enable big selects, you could reform this using correlated sub-queries. (I don't know if you'll still hit the limit or not though.)
SELECT DISTINCT
new_movies.*,
movies_db.*,
(SELECT rating FROM ratings WHERE new_movies.mid = ratings.mid) AS rating,
(SELECT count FROM ratings WHERE new_movies.mid = ratings.mid) AS rating_count,
(SELECT color FROM colors WHERE new_movies.mid = colors.mid) AS colour,
(SELECT rating FROM critic_ratings WHERE new_movies.mid = critic_ratings.mid) AS critic_ratings
FROM
new_movies
INNER JOIN
movies_db
ON new_movies.mid = movies_db.mid
ORDER BY
title ASC
Also, worth a test to see if the LEFT JOINs are actually the cause, can you execute the following?
SELECT DISTINCT
new_movies.*,
movies_db.*
FROM
new_movies
INNER JOIN
movies_db
ON new_movies.mid = movies_db.mid
ORDER BY
title ASC
why do you have a movies and a new_movies table? surely a release date field would be sufficient for that - would cut out a join too...
to that end I would create a view of that data and query that instead.
But back to your query:
SELECT DISTINCT
new_movies.*,
movies_db.*,
ratings.rating,
ratings.count,
color,
critic_ratings.rating AS critic_ratings
FROM
new_movies
INNER JOIN
movies_db
ON
new_movies.mid = movies_db.mid
LEFT JOIN
ratings
ON
new_movies.mid = ratings.mid
LEFT JOIN
colors
ON
new_movies.mid = colors.mid
LEFT JOIN
critic_ratings
ON
new_movies.mid = critic_ratings.mid
ORDER BY
title ASC
I can't see anything obvious... perhaps you can post the results of an explain query?
There is no problem with your query per se. It's just that you're selecting all movies (no WHERE, no LIMIT) and since you're joining ratings for e.g., it will join all ratings to each movie. You are just reaching the max amount of data allowed for joins.
I'm not sure why you'd need to select all movies. Perhaps you can use a limit. Otherwise you can just try the solutions in the error message.