select all row except those specified in the subquery - mysql

I make a selection on request and it behaves correctly.
SELECT t1.id, MIN(t1.rate)
FROM offers AS t1
WHERE t1.stock > 0
GROUP BY t1.ean;
AS soon as I nest it in another query, then the difficulty arises that WHERE NOT IN expects one column, but I need to keep MIN for GROUP BY to be preserved.
Here is query:
SELECT t2.id, t2.name, t2.ean
FROM offers AS t2
WHERE t2.id NOT IN (SELECT t1.id, MIN(t1.rate)
FROM offers AS t1
WHERE t1.stock > 0
GROUP BY t1.ean);

So here is answer:
SELECT t1.id
FROM offers AS t1
WHERE t1.id NOT IN (
SELECT f.id
FROM (SELECT
ean,
Min(net_price) AS minprice,
stock
FROM offers
GROUP BY ean
)
AS x INNER JOIN offers
AS f ON f.ean = x.ean AND f.net_price = x.minprice);

Related

Join with column outside subquery

SELECT t1.name as r_name, t1.values as r_values
FROM table as t1
JOIN (
SELECT SUM(amount) as amount
FROM database2.table
WHERE ids IN (t1.values)
) as t2
WHERE t1.id = 20;
I get an error, that t1.values inside the subquery is unknown column.
You need to rewrite your query and take inne where to join condition:
SELECT t1.name as r_name, t1.values as r_values
FROM table as t1
JOIN (
SELECT SUM(amount) as amount
FROM database2.table
) as t2 ON t2.ids = t1.values
WHERE t1.id = 20;
Also, you don't use amount column, so what is the point of join?
Another issue, you don't have any join condition defined.
I think you need to read about joins in SQL first :)
It seems you are trying to join database2.table to your t1 based on t1.values list.
I added group by IDs in t2 since your using aggregation function. Then, not sure what's the purpose of your sum(amount)
SELECT t1.name as r_name, t1.values as r_values
FROM table as t1
JOIN (
SELECT SUM(amount) as amount, ids
FROM database2.table
GROUP BY ids
) as t2 on t2.ids IN (t1.values)
WHERE t1.id = 20;

Get id of the record having Min() value

I have a complex mysql query where one of the Select fields is Min(value). Since all the 'values' are unique, is there also a way to get found min value's row id along?
In other words if we simplify the query to this question, it is like this:
SELECT t1.name, MIN(t2.value) AS minval
FROM table1 t1
LEFT JOIN table2 t2
ON t2.id_user = t1.id
GROUP BY id_user
How can i now know which t2.id was chosen for lowest t2.value for particular user? Thank you!
Use ROW_NUMBER() to find the first value of each id_user
You can replace * with the fields you need
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY t2.id_user ORDER BY t2.value) as rnk
FROM table1 t1
LEFT JOIN table2 t2
ON t2.id_user = t1.id
) as X
WHERE X.rnk = 1
Maybe this simple, dont know how complex your statement is:
SELECT name,value,id
FROM(
SELECT t1.name,t2.value,t2.id
FROM table1 t1
LEFT JOIN table2 t2
ON t2.id_user = t1.id
GROUP BY t2.id,id_user
ORDER BY t1.name,t2.id asc) as test
GROUP BY name;

Joining three tables such that extra matches are discarded?

How can I write a query to give the results of three tables such that there's only one result per "line"?
The tables are:
T1 (ID, name, IP)
T2 (ID, date_joined)
T3 (ID, address, date_modified)
The relations are:
T1-T2 1:1, T1-T3 1:M - there can be many address rows per ID in T3.
What I want is a listing of all users with the fields above, but IF they have an address, I only want to record ONE (bonus would be if it is the latest one based on T3.date_modified).
So I should end up with exactly the number of records in T1 (happens to be equal to T2 in this case) and no more.
I tried:
select t.ID, t.name, t.IP, tt.ID, tt.date_joined, ttt.ID, ttt.address
from T1 t JOIN T2 tt ON (t.ID = tt.ID) JOIN T3 ttt ON (t.ID = ttt.ID)
And every sensible combination of LEFT, RIGHT, INNER, etc joins I could think of! I keep getting multiple duplicate because of T3
This query should work:
select
t1.ID, t1.name, t1.IP, t2.date_joined, t3x.address
from t1
join t2 on t1.ID = t2.id
left join (
select t3.*
from t3
join (
select id, max(date_modified) max_date
from t3
group by id
) max_t3 on t3.id = max_t3.id and t3.date_modified = max_t3.max_date
) t3x on t1.ID = t3x.id
First you do the normal join between t1 and t2 and then you left join with a derived table (t3x) that is the set of t3 rows having the latest date.
So T2 is actually not relevant here. You just need a way to join from T1 to T3 in a way that gets you at most one T3 row per T1 row.
One way of doing this would be:
select
T1.*,
(select address from T3 where T3.ID=T1.ID order by date_modified desc limit 1)
from T1;
This won't likely be very efficient, being a correlated subquery, but you may not care depending on the size of your dataset.
It's also only good for getting one column from T3, so if you had Address, City, and State, you'd have to figure out something else.
You can use sub query with Top 1 so that u get only one result from T3
here is a sample sql
select * into #T1 from(
select 1 ID
union select 2
union select 3) A
select * into #T2 from(
select 1 ID
union select 2
union select 3) A
select * into #T3 from(
select 1 ID, 'ABC' Address, getDate() dateModified
union select 1, 'DEF', getDate()
union select 3, 'GHI', getDate()) A
select *, (select top 1 Address from #T3 T3 where T3.ID= T1.ID order by datemodified desc) from #T1 T1
inner join #T2 T2 on T1.ID = T2.ID
Bonus :- you can also add order by dateModified desc to get the latest address

From MYSQL SELECT to a MYSQL VIEW

I don't know how to make this.
Background:
Profiles -> table with user profiles
Score -> table with users' score (One user can have multiple scores) (This table has a created_at field to know when I introduce the new score)
Imagine that score table save klout score data.
How do convert this query to a view?
SELECT t1.id,
t1.name,
t1.screen_name,
t1.description,
t1.url,
t1.statuses_count,
t1.followers_count,
t1.friends_count,
t1.listed_count,
t1.favourites_count,
t1.utc_offset,
t1.time_zone,
t1.verified,
t1.lang,
t1.profile_image_url,
t1.geo_enabled,
t1.location,
t1.lat,
t1.lng,
t1.created_at,
t3.score,
t3.delta,
t3.detail
FROM profiles t1 LEFT JOIN (SELECT t2.user_id, t2.score, t2.delta, t2.detail
FROM scores t2
ORDER BY t2.created_at DESC)
AS t3 ON t3.user_id = t1.id
GROUP BY t1.id
The problem VIEW cannot contain subquery, the subquery in your query can be directly join on the table since you haven't perform any aggregation.
CREATE VIEW viewName
AS
SELECT t1.id,
t1.name,
t1.screen_name,
t1.description,
t1.url,
t1.statuses_count,
t1.followers_count,
t1.friends_count,
t1.listed_count,
t1.favourites_count,
t1.utc_offset,
t1.time_zone,
t1.verified,
t1.lang,
t1.profile_image_url,
t1.geo_enabled,
t1.location,
t1.lat,
t1.lng,
t1.created_at,
t3.score,
t3.delta,
t3.detail
FROM profiles t1
LEFT JOIN scores t3
ON t3.user_id = t1.id
-- GROUP BY t1.id
I can't get why you have a GROUP BY clause in your query.
You can split your code into 2 views
View 1:
CREATE VIEW step1
AS
SELECT t2.user_id, t2.score, t2.delta, t2.detail
FROM scores t2
ORDER BY t2.created_at DESC
View 2:
CREATE VIEW step2
AS
SELECT t1.id,
t1.name,
t1.screen_name,
t1.description,
t1.url,
t1.statuses_count,
t1.followers_count,
t1.friends_count,
t1.listed_count,
t1.favourites_count,
t1.utc_offset,
t1.time_zone,
t1.verified,
t1.lang,
t1.profile_image_url,
t1.geo_enabled,
t1.location,
t1.lat,
t1.lng,
t1.created_at,
t3.score,
t3.delta,
t3.detail
FROM profiles t1
LEFT JOIN step1 AS t3 ON t3.user_id = t1.id
GROUP BY t1.id
I am not sure why you are grouping by t1.id, but maybe there's something in your data that I don't know about

In MySQL, how to use a subquery to a left join statement?

I tried to count how many new tuples are in a subset of t2 as compared to t1 by
SELECT
COUNT(t2.id)
FROM (
(SELECT id, col1 FROM t2 WHERE col2=0 AND col3=0) AS t
LEFT OUTER JOIN
t1
ON
t.id=t1.id
)
WHERE
t1.id IS NULL;
The subset is defined by
(SELECT id, col1 FROM t2 WHERE col2=0 AND col3=0) AS t
But the above program doesn't seem to work, issuing errors.
There is no need to enclose the FROM clause in (). You are referencing t2.id in your aggregate COUNT(), but your SELECT list will only produce t.id from the subquery that encapsulates t2. This version addresses the source of your errors:
SELECT
COUNT(t.id) AS idcount
FROM
(SELECT id, col1 FROM t2 WHERE col2=0 AND col3=0) AS t
LEFT OUTER JOIN t1 ON t.id = t1.id
WHERE t1.id IS NULL
However:
Since your subquery is actually pretty simple, I believe it isn't necessary at all. The whole thing can be done with a LEFT JOIN:
SELECT
/* The equivalent of COUNT(*) in this context */
COUNT(t2.id) AS idcount
FROM
t2
LEFT OUTER JOIN t1 ON t2.id = t1.id
WHERE
t1.id IS NULL
AND (t2.col2 = 0 AND t2.col3 = 0)
are you sure you don't want to do COUNT(t.id)? t2 is in a subquery and is not available to the main query only t and t1 are available.
The problem is the alias. You have:
select count(t2.id)
But, t2 is defined in the subquery, so it is out of scope.
You want:
select count(t.id)