Mysql: how to get Inverse result for given condition? - mysql

I wrote a query to get exactly opposite of result, what my query produces.
query 1:
select count(*) from DB.titlecard tt
join _date d on d.td_id = tt.td_id
join sometask s on s.s_id = tt.s_id and d.em_id = s.em_id
where d.`date` > "2019-01-01";
it gives me count of 21354 result.
query 2: (Similar query without sometask join)
select count(*) from DB.titlecard tt
join _date d on d.td_id = tt.td_id
where d.`date` > "2019-01-01";
which produces 28984
i need records which is difference of query 2 - query 1
something like this,
but it gives 1000 000 records.
select count(*) from DB.titlecard tt
join _date d on d.td_id = tt.td_id
join sometask s on s.s_id <> tt.s_id and d.em_id = s.em_id
where d.`date` > "2019-01-01";
i know to get difference by comparing both query.
but i am looking for better way within single query (because i have added only one more table in query 1)
this alone was the difference,
query 1:
join sometask s on s.s_id = tt.s_id
condition i want to apply,
join sometask s on s.s_id <> tt.s_id

If you change your JOIN to a LEFT JOIN and then select only the rows where s.id is NULL you will get the count you want:
select count(*) from DB.titlecard tt
join _date d on d.td_id = tt.td_id
left join sometask s on s.s_id = tt.s_id and d.em_id = s.em_id
where d.`date` > "2019-01-01" and s.s_id IS NULL;

This can be quite complicated -- particularly if there are NULL values or duplicate rows. I am guessing, though, that this does what you want:
select count(*) - count(s.s_id)
from DB.titlecard tt join
d
on d.td_id = tt.td_id left join
sometask s
on s.s_id = tt.s_id and d.em_id = s.em_id
where d.`date` > '2019-01-01';

Related

Use AVG result in select subquery

I have a rating system in my app. Now I'm trying to get all AVG results from the ratings. Every AVG result has a result (in text) that I need to grab from the rating_results table.
It looks like this:
select round(avg(rating_results.rating)) as ratingresult, count(*) as votes, score.question_nl,
(select result_nl from rating_results where rating_results.rating = ratingresult and rating_results.score_id = score.id) from score
inner join score_categories on score_categories.id = score.category_id
inner join rating ON score.id = rating.score_id
inner join rating_results on rating.rating_result_id = rating_results.id
inner join dog on dog.id = rating.ratable_id
where dog.breed_id = 201
group by score.question_nl
The problem I have is that I cannot use ratingresult in the subselect.
Query 1 ERROR: Reference 'ratingresult' not supported (reference to
group function)
I already tried a lot but can't figure out another way.
Could use some help here, thanks!
--EDIT
The rating result explains the rating. So if the AVG rating is 4 then in the rating_results table I can find what that rating means:
Instead of a select for column value you could use a subquery for avg in join
select t.ratingresult
, count(*) as votes
, score.question_nl
, rating_results.result_nl
FROM score
inner join score_categories on score_categories.id = score.category_id
inner join rating ON score.id = rating.score_id
inner join rating_results on rating.rating_result_id = rating_results.id
inner join dog on dog.id = rating.ratable_id
INNER JOIN (
select round(avg(rating_results.rating)) as ratingresult
, score.question_nl
from score
inner join rating ON score.id = rating.score_id
inner join rating_results on rating.rating_result_id = rating_results.id
group by score.question_nl
) t ON t.ratingresult = rating_results.rating
AND rating_results.score_id = score.id
AND score.question_nl = t.question_nl
where dog.breed_id = 201
group by score.question_nl, t.ratingresult
avoinding subquery

Sql query within an inner join

i have this mysql statement :
SELECT ca.*, MAX(ca.id), v.*,a.submit_dt from callback_holding ca
inner join valuations v on v.Ref = ca.ref
inner join answer a on a.title = ca.ref
where v.Consultant = '$user' and ca.isholding = 2
GROUP BY ca.ref DESC order by ca.reccomendeddate asc
But the problem is if there is not an entry in "answer" then it doesn't show up in the list. What is the correct way to bring back everything and just "null" if there is nothing in the "answer" table?
Thanks
Your query has several problems. First, you are grouping by the ref column from the callback_holding table, but are selecting non aggregate columns not only from this table, but from other tables. To get around this, you should do the aggregation to find maximum IDs in callback_holding in a subquery, and then join it to the other tables.
Next, you mentioned that if no answer be found, you get back no records. This is the nature of an INNER JOIN, but if you switch the join to answer to use a LEFT JOIN, then no records up to that point in the query will be lost. Note that I used COALESCE(a.submit_dt, 'NA') to display NA in the event that this column from the answer table be NULL. If this column be datetime, then you should use a suitable default value, e.g. NOW().
SELECT ca.*,
v.*,
COALESCE(a.submit_dt, 'NA') AS submit_dt, -- display 'NA' if no answer
t.max_id
FROM callback_holding ca
INNER JOIN
(
SELECT ref, MAX(id) AS max_id
FROM callback_holding
GROUP BY ref
) t
ON t.ref = ca.ref AND
t.max_id = ca.id
INNER JOIN valuations v
ON v.Ref = ca.ref
LEFT JOIN answer a
ON a.title = ca.ref
WHERE v.Consultant = '$user' AND
ca.isholding = 2
ORDER BY ca.reccomendeddate
try with:
SELECT ca.*, MAX(ca.id), v.*,a.submit_dt from callback_holding ca
INNER join valuations v on v.Ref = ca.ref
LEFT join answer a on a.title = ca.ref
WHERE v.Consultant = '$user' and ca.isholding = 2
GROUP BY ca.ref DESC order by ca.reccomendeddate asc

Count matched words from IN operator

i have this little mysql query :
select t.title FROM title t
inner join movie_keyword mk on mk.movie_id = t.id
inner join keyword k on k.id = mk.keyword_id
where k.keyword IN (
select k.keyword
FROM title t
inner join movie_keyword mk on mk.movie_id = t.id
inner join keyword k on k.id = mk.keyword_id
where t.id = 166282
)
LIMIT 15
as you can see it will return all titles from title that have at least one the same keyword that have movie with id 166282.
Now i have problem, because i want also count how many keywords was matched in IN operator(let's say i want to see only titles that have 3 or more the same keywords), i tried something with aggregate functions, but everything failed, so i came here with my problem. Maybe somebody can give me some advice, or code example.
I'm not also sure, if this "subquery way" is good, so if there are some better options how i should solve my problem, I am open to any suggestions or tips.
Thank you!
#Edit
So after some problems, i have one more. This is my current query :
SELECT s.title,s.vote,s.rating,count(dk.key) as keywordCnt, count(dg.name) as genreCnt
FROM series s
INNER JOIN series_has_genre shg ON shg.series_id = s.id
INNER JOIN dict_genre dg ON dg.id = shg.dict_genre_id
INNER JOIN series_has_keyword shk ON shk.series_id = s.id
INNER JOIN dict_keyword dk ON dk.id = shk.dict_keyword_id
WHERE dk.key IN (
SELECT dki.key FROM series si
INNER JOIN series_has_keyword shki ON shki.series_id = si.id
INNER JOIN dict_keyword dki ON dki.id = shki.dict_keyword_id
WHERE si.title LIKE 'The Wire'
)
and dg.name IN (
SELECT dgo.name FROM series so
INNER JOIN series_has_genre shgo ON shgo.series_id = so.id
INNER JOIN dict_genre dgo ON dgo.id = shgo.dict_genre_id
WHERE so.title LIKE 'The Wire'
)
and s.production_year > 2000
GROUP BY s.title
ORDER BY s.vote DESC, keywordCnt DESC ,s.rating DESC, genreCnt DESC
LIMIT 5
Problem is, it is very, very, very slow. Any tips what i should change, to run it faster ?
Will this work for you:
select t.title, count(k.keyword) as keywordCount FROM title t
inner join movie_keyword mk on mk.movie_id = t.id
inner join keyword k on k.id = mk.keyword_id
where k.keyword IN (
select ki.keyword
FROM title ti
inner join movie_keyword mki on mki.movie_id = ti.id
inner join keyword ki on ki.id = mki.keyword_id
where ti.id = 166282
) group by t.title
LIMIT 15
Note that I have changed the table names inside the nested query to avoid confusion.

MySQL using COUNT, LEFT JOIN and GROUP by returning undesired results

I need some help to get the desired results, which would in this case, be 7 (the number of rows in the products table that would match).
What I am instead getting is 7 rows with a count based on the the number of rows returned in the LEFT JOIN.
SELECT count(p.id) as theCount
FROM products p
left join tablea a on p.id = a.productId
left join tableb b on p.id = b.productId
WHERE (a.col = 'val' or b.col = 'val')
group by p.id
If I do not group by p.id, I get back 28 rows, which is all of the rows from the LEFT JOIN.
I know it's something simple, but I can't figure it out.
Thanks.
select count(distinct p.id), perhaps? Since you're pulling from two different tables, you're going to get a mismash of (p.id, a.col, b.col) being (xxx, null, yyy) and (xxx, yyy, null)
You shouldn't join the one-to-many relationships if all you want is the count of products.
Put your filter condition in the WHERE clause.
SELECT count(*) as theCount
FROM products p
WHERE p.id IN (
SELECT a.productId
FROM tablea a
WHERE a.productId = p.id AND a.col = 'val'
UNION
SELECT b.productId
FROM tableb b
WHERE b.productId = p.id AND b.col = 'val'
)

MySQL GROUP BY performance issue

This is the query I'm performing (without some Joins that are not relevant):
SELECT a.*, c.id
FROM a
LEFT OUTER JOIN b ON a.id = b.id_anunciante
LEFT OUTER JOIN c ON c.id = b.id_rubro
GROUP BY a.id
Each row of "a" is linked with 1 to 5 rows in "b".
The problem is that GROUP BY has performance issues (it takes 10x or more using GROUP BY than not using it). I need to retrieve only one row of each member in "a".
How can I make this faster?
edit: I need to be able to filter by a.id AND/OR c.id. The resultset I should be getting is only 1 row per "valid" member of "a", meaning the rows that match the constraints. Rows that don't match the filters shouldn't be returned.
In my original query, this would be done this way:
SELECT a.*, c.id
FROM a
LEFT OUTER JOIN b ON a.id = b.id_anunciante
LEFT OUTER JOIN c ON c.id = b.id_rubro
WHERE c.id = 1
OR a.id = 1
GROUP BY a.id
a.id, b.id_anunciante, b.id_rubro, c.id are all indexes.
SELECT a.*,
(
SELECT c.id
FROM b
JOIN с
ON c.id = b.id_rubro
WHERE b.id_anunciante = a.id
-- add the ORDER BY condition to define which row will be selected.
LIMIT 1
)
FROM a
Create the index on b (id_anunciante) for this to work faster.
Update:
You don't need the OUTER JOINs here.
Rewrite your query as this:
SELECT a.*, c.id
FROM a
JOIN b
ON b.id_anunciante = a.id
JOIN c
ON c.id = b.id_rubro
WHERE a.id = 1
UNION ALL
SELECT a.*, 1
FROM a
WHERE EXISTS
(
SELECT NULL
FROM c
JOIN b
ON b.id_rubro = c.id
WHERE c.id = 1
AND b.id_anunciante = a.id
)
Add ORDER BY NULL to avoid the implicit sorting MySQL does when doing a group by.
I suppose you have indexes/PKs on a.id, b.id_anunciante, b.id_rubro and c.id ? I guess you could try adding a composite index on (b.id_anunciante, b.id_rubro) if your mysql version is not able to do an index merge.