Doctrine SQL query: works on MySQL, on PostgreSQL won't - mysql

This is a query automatically generated by Taggable extension for Doctrine ORM.
SELECT t.id AS t__id, t.name AS t__name, COUNT(DISTINCT i.id) AS i__0,
(COUNT(DISTINCT i.id)) AS i__1
FROM taggable_tag t
LEFT JOIN cms__model__image_taggable_tag c ON (t.id = c.tag_id)
LEFT JOIN image i ON i.id = c.id
WHERE t.id IN
(SELECT doctrine_subquery_alias.id
FROM
(SELECT DISTINCT t2.id, (COUNT(DISTINCT i2.id)) AS i2__1
FROM taggable_tag t2
LEFT JOIN cms__model__image_taggable_tag c2 ON (t2.id = c2.tag_id)
LEFT JOIN image i2 ON i2.id = c2.id
GROUP BY t2.id HAVING i2__1 > 0
ORDER BY i2__1 DESC LIMIT 10) AS doctrine_subquery_alias)
GROUP BY t.id HAVING i__1 > 0
ORDER BY i__1 DESC
It works when using MySql, but won't work with PostgreSql.
I get: column i2__1 not found or column i__2 not found.
Are aliases disallowed when using COUNT(DISTINCT)?
How this query should look like to work on PostgreSql?

You could try to replace i2__1 by COUNT(DISTINCT i2.id) in the HAVING-clause of the sub-select, or remove the parenthesis around COUNT(DISTINCT i2.id).
You might also have to add t__name to the GROUP BY-clause of the main select.

Related

SQL query gets stuck if adding ORDER BY

I am working with a query, which looks like this
SELECT s.c1, s.t, s.u, s.dt, t.temp, t.dt AS dt2
FROM `systemusage` AS s
INNER JOIN temperature AS t ON s.did=t.did
WHERE t.did = (SELECT id FROM devices WHERE m = 1)
LIMIT 1
Which works just fine, however if I add ORDER BY s.id, then the query gets totally stuck, can someone guide me on why? the id field is primary, so it should be indexed no?
Add an index on the column temperature.did so that the WHERE clause can be implemented efficiently.
It also may help to replace WHERE t.did = (SELECT ...) with a JOIN.
SELECT s.c1, s.t, s.u, t.temp
FROM `systemusage` AS s
INNER JOIN temperature AS t ON s.did=t.did
INNER JOIN devices AS d ON d.id = t.did
WHERE d.m = 1
ORDER BY s.id DESC, t.id DESC
LIMIT 1

How to correctly use group_concat to concatenate Join query result in MYSQL?

I have written the following MYSQL query and the The Mysql version is 8.0.18-commercial
SELECT p.server, 'Type_ABC' AS Check_Type, COALESCE(vmtable.res) AS result
FROM server p
INNER JOIN truns t ON t.oq_id = p.oq_id
AND t.id = (SELECT t2.id FROM truns t2 WHERE t2.oq_id = p.oq_id order by t2.created_at desc limit 1 )
INNER JOIN qvuln_info vmtable ON vmtable.run_id = t.id
LEFT JOIN qvuln_info_data vmtableinfo ON vmtableinfo.qid = vmtable.qid
WHERE p.server regexp 'server1';
I am getting following output from the above query:
Hostname Check_Type result
server1 Type_ABC Result 1
server1 Type_ABC Result 2
server1 Type_ABC Result 3
server1 Type_ABC Result 4
I want to concatenate the results so that the output should look as below:
Hostname Check_Type result
server1 Type_ABC Result 1,,Result 2,,Result 3,,Result 4
To achieve the above output, I have written the following query but it is giving syntax error:
SELECT p.server, 'Type1' AS Check_Type,
GROUP_CONCAT((COALESCE(vmtable.res) AS result) SEPARATOR ', ')
FROM server p
INNER JOIN truns t ON t.oq_id = p.oq_id
AND t.id = (SELECT t2.id FROM truns t2 WHERE t2.oq_id = p.oq_id order by t2.created_at desc limit 1 )
INNER JOIN qvuln_info vmtable ON vmtable.run_id = t.id
LEFT JOIN qvuln_info_data vmtableinfo ON vmtableinfo.qid = vmtable.qid
WHERE p.server regexp 'server1';
How to correctly use GROUP_CONCAT with COALESCE?
You're missing a GROUP BY clause on your query; you need to GROUP BY p.server. Note that your COALESCE isn't actually doing anything as you haven't provided a value to replace with if the value is NULL, so you may as well leave it out (since GROUP_CONCAT ignores NULL values, this will prevent any values appearing in the result when vmtable.res is NULL). Your query should look like:
SELECT p.server, 'Type1' AS Check_Type,
GROUP_CONCAT(vmtable.res SEPARATOR ', ') AS result
FROM server p
INNER JOIN truns t ON t.oq_id = p.oq_id
AND t.id = (SELECT t2.id FROM truns t2 WHERE t2.oq_id = p.oq_id order by t2.created_at desc limit 1 )
INNER JOIN qvuln_info vmtable ON vmtable.run_id = t.id
LEFT JOIN qvuln_info_data vmtableinfo ON vmtableinfo.qid = vmtable.qid
WHERE p.server regexp 'server1'
GROUP BY p.server
Also note that the AS result should have been outside the GROUP_CONCAT.

MySQL - Ordering IN within INNER JOIN

I'm creating a system that allows a user to search a database of photo albums images for a keyword, it's working great, the only issue is that I'm ordering relevancy by the amount of times that keyword appears in an album. I'm doing this using:
SELECT collections_ids.collection_id
FROM `keywords`
INNER JOIN collections_ids ON keywords.id = collections_ids.photo_id
WHERE keywords.`keyword` = 'trees'
GROUP BY collection_id
ORDER BY COUNT(*) DESC
As said, this works great.
The only issue is, when this is included in an "WHERE IN" query, it loses it's order and is returned randomly. For clarity, here is the query:
SELECT collections.id,
collections.title
images.img_small
FROM `collections`
INNER JOIN images ON images.id = collections.cover_photo
WHERE collections.`id` IN
(SELECT collections_ids.collection_id
FROM `keywords`
INNER JOIN collections_ids ON keywords.id = collections_ids.photo_id
WHERE keywords.`keyword` = 'trees'
GROUP BY collection_id
ORDER BY COUNT(*) DESC)
I've tried researching, and people have suggested using the FIELD function, but I don't see that working in this context.
Any suggestions?
you can use sub query as join and take it count(*) as order by like below
SELECT collections.id,
collections.title
images.img_small
FROM `collections`
INNER JOIN images ON images.id = collections.cover_photo
INNER JOIN
(SELECT distinct collections_ids.collection_id As collection_id,COUNT(*) as total
FROM `keywords`
INNER JOIN collections_ids ON keywords.id = collections_ids.photo_id
WHERE keywords.`keyword` = 'trees'
GROUP BY collection_id
) as A
ON A.collection_id =collections.collection_id
order by A.total

MySql order by clause not working

In mysql query I use order by, but it is not working.
When I do this
SELECT t.id,t.user_id,t.title,c.comment,d.has_answer,IF(c.id IS NULL, t.date_created, d.recent_date) recent_date,MIN(i.id) image_id
FROM threads t
LEFT JOIN comments c ON c.thread_id = t.id
INNER JOIN (
SELECT thread_id, MAX(date_sent) recent_date, MAX(is_answer) has_answer
FROM comments
GROUP BY thread_id
) d ON c.id IS NULL OR (d.thread_id = c.thread_id AND d.recent_date = c.date_sent)
LEFT JOIN thread_images i ON t.id = i.thread_id
WHERE t.user_id = t.user_id
GROUP BY t.id
ORDER BY d.recent_date DESC
LIMIT 0, 10
It doesn't properly order them. But if I do this:
SELECT *
FROM (
SELECT t.id,t.user_id,t.title,c.comment,d.has_answer,IF(c.id IS NULL, t.date_created, d.recent_date) recent_date,MIN(i.id) image_id
FROM threads t
LEFT JOIN comments c ON c.thread_id = t.id
INNER JOIN (
SELECT thread_id, MAX(date_sent) recent_date, MAX(is_answer) has_answer
FROM comments
GROUP BY thread_id
) d ON c.id IS NULL OR (d.thread_id = c.thread_id AND d.recent_date = c.date_sent)
LEFT JOIN thread_images i ON t.id = i.thread_id
WHERE t.user_id = t.user_id
GROUP BY t.id
LIMIT 0, 10) qwerty
ORDER BY recent_date DESC
Then it does work. Why does the top one not work, and is the second way the best way to fix that?
Thanks
Those two statements are ordering by two different things.
The second statement is ordering by the result of an expression in the SELECT list.
But the first statement specifies ordering by a value of recent_date returned by the inline view d; if you remove "d." from in front of recent_date, then the ORDER BY clause would reference the alias assigned to the expression in the SELECT list, as the second statement does.
Because recent_date is an alias for an expression the SELECT list, these two are equivalent:
ORDER BY recent_date
ORDER BY IF(c.id IS NULL, t.date_created, d.recent_date)
^^
but those are significantly different from:
ORDER BY d.recent_date
^^
Note that the non-standard use of the GROUP BY clause may be masking some values of recent_date which are discarded by the query. This usage of the GROUP BY clause is a MySQL extension to the SQL Standard; most other relational databases would throw an error with this statement. It's possible to get MySQL to throw the same type of error by enabling the ONLY_FULL_GROUP_BY SQL mode.
Q Is the second statement the best way to fix that?
A If that statement guarantees that the resultset returned meets your specification, then it's a workable approach. (One downside is the overhead of the inline view query.)
But I strongly suspect that the second statement is really just masking the problem, not really fixing it.
SELECT t.id,t.user_id,t.title,c.comment,d.has_answer,IF(c.id IS NULL, t.date_created, d.recent_date) recent_date,MIN(i.id) image_id
FROM (threads t
LEFT JOIN comments c ON c.thread_id = t.id
INNER JOIN (
SELECT thread_id, MAX(date_sent) recent_date, MAX(is_answer) has_answer
FROM comments
GROUP BY thread_id
) d ON c.id IS NULL OR (d.thread_id = c.thread_id AND d.recent_date = c.date_sent)
LEFT JOIN thread_images i ON t.id = i.thread_id
WHERE t.user_id = t.user_id
GROUP BY t.id
LIMIT 0, 10) x
ORDER BY d.recent_date DESC

Apply ORDER BY after query and LIMIT

Have found similar posts but still stuck - I am trying to apply a sort AFTER I have processed a query and limited the results. My code is
select DISTINCT(t.id) t_id, t.cart_id ,tS.id tS_id, tS.created tS_created, t.value, t.transactionType_id tT_id, tS.member_name, outIn, tT.type type
from(transaction t)
join transactionSummary tS ON tS.id = t.transactionSummary_id
left join transactionType tT ON tT.id = t.transactionType_id
order by t.id DESC
limit 50
I have tried doing a sub select and applying the ORDER BY afterwards but get an error saying Unknown column 't.id' in 'field list'.
The above code (ie without the sub select) works fine but the ORDER BY slows it down so much as the table is huge...
Any suggestions?
Since you're aliasing t.id to t_id, you need to use the alias in the outer query.
SELECT *
FROM (select DISTINCT t.id t_id, t.cart_id ,tS.id tS_id, tS.created tS_created, t.value, t.transactionType_id tT_id, tS.member_name, outIn, tT.type type
from transaction t
join transactionSummary tS ON tS.id = t.transactionSummary_id
left join transactionType tT ON tT.id = t.transactionType_id
limit 50) x
ORDER BY t_id DESC
BTW, the way you wrote DISTINCT(t.id) suggests that you think the distinct operation is only being applied to that one column. DISTINCT applies to the entire SELECT list; if you only want to make certain columns distinct, you must use GROUP BY to specify those columns.
Here's a possible way to rewrite the query that may make it faster:
select DISTINCT t.id t_id, t.cart_id ,tS.id tS_id, tS.created tS_created, t.value, t.transactionType_id tT_id, tS.member_name, outIn, tT.type type
from transaction t
join (select max(id)-500 maxid from transaction) mT on t.id > maxid
join transactionSummary tS ON tS.id = t.transactionSummary_id
left join transactionType tT ON tT.id = t.transactionType_id
order by t_id DESC
limit 50
By filtering down to just the top 500 IDs, the size of the joins and sorting are reduced.