Error while compiling statement: FAILED: SemanticException [Error 10002] - mysql

select d.order_type from migu_td_aaa_order_log_d d where exists(select 1
from migu_user r where r.user_id = '156210106' and r.user_num =
d.serv_number) and d.product_id in ('2028594290','2028596512','2028597138' )
order by d.opr_time desc limit 1
why the above sql failed ,indicates :
FAILED: SemanticException [Error 10002]: Line 4:11 Invalid column reference 'opr_time'
but the below one works :
select temp.order_type from (
select d.* from migu_td_aaa_order_log_d d where exists(select 1 from
migu_user r where r.user_id = '156210106' and r.user_num = d.serv_number)
and d.product_id in ('2028594290','2028596512','2028597138' ) order by
d.opr_time desc limit 1) temp;
this one works fine ,too ,and much more efficient than the second one:
select d.* from migu_td_aaa_order_log_d d where exists(select 1 from
migu_user r where r.user_id = '156210106' and r.user_num = d.serv_number)
and d.product_id in ('2028594290','2028596512','2028597138' )
order by d.opr_time desc limit 1
I only need to get order_type field,so even though the second one works,but it cost much more time.
Can anyone help me?
Thanks a lot!

Your first query does not work because, in the first select statement, you are just getting one column (d.order_type), but you are trying to order by another column (d.opr_time), which you have not included in your select statement
select d.order_type from ...
...
order by d.opr_time desc limit 1
Note that if you added the column d.opr_time to your first query, it would work:
select d.order_type, d.opr_time from ...
...
order by d.opr_time desc limit 1
Your second query works because, in the subquery, you have selected all the columns of d (d.*), so when you order by opr_time, that column is present. (Same for the third query).
select temp.order_type from (
select d.* ... order by d.opr_time ...
EDITED:
According to the Hive documentation:
When using group by clause, the select statement can only include
columns included in the group by clause. Of course, you can have as
many aggregation functions (e.g. count) in the select statement as
well.
So, this query:
select d.order_type, d.opr_time from ...
...
order by d.opr_time desc limit 1
Shouldn't work either, because the select clause has an additional column (d.order_type) that is not included in the group by clause.
I hope this helps.
P.S. This answer about SQL execution order might be useful.

1.
Hive currently have an order by limitation.
The current status of this issue is PATCH AVAILABLE.
see -
"Can't order by an unselected column"
https://issues.apache.org/jira/browse/HIVE-15160
2.
You might want to get familiar with LEFT SEMI JOIN which is a cleaner syntax for EXISTS
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Joins#LanguageManualJoins-JoinSyntax
3.
using min / max over a struct / named_struct can be used instead of order by ... asc / desc and limit 1
Here is an alternative solution:
select max(named_struct('opr_time',d.opr_time,'order_type',d.order_type)).order_type
from migu_td_aaa_order_log_d d
left semi join migu_user r
on r.user_num =
d.serv_number
and r.user_id = '156210106'
where d.product_id in ('2028594290','2028596512','2028597138')
;
P.s.
You seriously want to consider to treat IDs (user_id, product_id) as numeric and not as strings.

Related

Difference query lastest result each group when using "group by" clause between MySQL 5.6 and 5.7

My question is that I used the same SQL query below on MySQL 5.6(Windows) and MySQL 5.7.21(Linux), got different results.
My requirement is getting the lastest row each group, the result from MySQL 5.6 did, but MySQL 5.7 did not get the latest row each group instead earliest row. It seems like that MySQL 5.7 optimized my query "FROM ( SELECT * FROM jc_content ORDER BY sort_date DESC ) cnt" without ordered.
I need MySQL 5.7 to get the same query result like 5.6 does. Is there any tricky I made mistakes?
SELECT
chn.channel_id,
CONCAT(
IFNULL(p_chn.channel_path, ''),
'/',
IFNULL(chn.channel_path, '')
) AS channel_path,
chnext.channel_name,
cnt.content_id,
cntex.title,
cntex.short_title,
cntex.release_date,
cntex.origin,
cntex.title_img,
cntex.type_img,
cntex.description AS descriptionStr,
cnt.sort_date
FROM
(
SELECT
*
FROM
jc_content
ORDER BY
sort_date DESC
) cnt
LEFT JOIN jc_content_ext cntex ON cnt.content_id = cntex.content_id
LEFT JOIN jc_channel chn ON chn.channel_id = cnt.channel_id
LEFT JOIN jc_channel p_chn ON chn.parent_id = p_chn.channel_id
LEFT JOIN jc_channel_ext chnext ON chnext.channel_id = cnt.channel_id
WHERE
cnt.`status` = 2
AND p_chn.channel_path = 'cp'
GROUP BY
channel_path
ORDER BY
cnt.sort_date DESC
Edited after asking;
Here is my solution, I found it out inadvertently. Just add "limit" after the derived query.
SELECT
chn.channel_id,
CONCAT(
IFNULL(p_chn.channel_path, ''),
'/',
IFNULL(chn.channel_path, '')
) AS channel_path,
chnext.channel_name,
cnt.content_id,
cntex.title,
cntex.short_title,
cntex.release_date,
cntex.origin,
cntex.title_img,
cntex.type_img,
cntex.description AS descriptionStr,
cnt.sort_date
FROM
(
SELECT
*
FROM
jc_content
ORDER BY
sort_date DESC
<em>LIMIT 100</em>
) cnt
LEFT JOIN jc_content_ext cntex ON cnt.content_id = cntex.content_id
LEFT JOIN jc_channel chn ON chn.channel_id = cnt.channel_id
LEFT JOIN jc_channel p_chn ON chn.parent_id = p_chn.channel_id
LEFT JOIN jc_channel_ext chnext ON chnext.channel_id = cnt.channel_id
WHERE
cnt.`status` = 2
AND p_chn.channel_path = 'cp'
GROUP BY
channel_path
ORDER BY
cnt.sort_date DESC
As you can see, when I add the limit it works. I tried to figure out and I used "EXPLAIN" SQL, It showed below:
enter image description here
Without "limit" by "EXPLAIN" it showed below:
enter image description here
Thus I could infer from the upons that MySQL 5.7 does optimize my query "FROM ( SELECT * FROM jc_content ORDER BY sort_date DESC ) cnt" without ordered, when I put limit behind, it becomes a derived table then it works. I used "EXPLAIN" on MySQL 5.6, it did not optimize the "FROM ( SELECT * FROM jc_content ORDER BY sort_date DESC ) cnt", it showed select_type of "DERIVED" and queried all rows.
Also I found the tricky point, once I changed the limit value, like "FROM ( SELECT * FROM jc_content ORDER BY sort_date DESC LIMIT 400 ) cnt", "EXPLAIN" that, it showed:
enter image description here
I tested the change of the limit value, I found that when the value is greater than 397, it would query all table rows(Total row count is 33021). Probably it's optimized mechanism of MySQL 5.7

SQL query - how to display the most common value only

I have recently started to learn sql queries but i am having some issues.
I have these two tables here:
Birds
http://i.imgur.com/2m0VuoE.png
MembersLikesBirdEncounter (birdID is the foriegn key here referenced from above table Birds)
http://i.imgur.com/0cWlG94.png
i am trying to display the most common birdID value from the table MembersLikesBirdEncounter, which is 234. Below is the query i have come up with which doesn't seem to be working. What am i doing wrong?
SELECT m.birdID, COUNT(m.birdID)
FROM MembersLikesBirdEncounter m, Birds b
WHERE b.birdID = m.birdID
GROUP BY m.birdID
ORDER BY m.birdID DESC
LIMIT 1;
I want the output to be
birdID
------
234
Not so hard...
Instead:
GROUP BY Count(m.birdID) DESC
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax. Then, the problem with your query is the ORDER BY column. You want to order by the count:
SELECT m.birdID, COUNT(m.birdID)
FROM MembersLikesBirdEncounter m JOIN
Birds b
ON b.birdID = m.birdID
GROUP BY m.birdID
ORDER BY COUNT(jm.birdID) DESC
LIMIT 1;
Then -- assuming that birdId refers always refers to valid birds -- the JOIN is not necessary. This should be sufficient:
SELECT m.birdID, COUNT(m.birdID)
FROM MembersLikesBirdEncounter m
GROUP BY m.birdID
ORDER BY COUNT(jm.birdID) DESC
LIMIT 1;

How to fix SQL query with Left Join and subquery?

I have SQL query with LEFT JOIN:
SELECT COUNT(stn.stocksId) AS count_stocks
FROM MedicalFacilities AS a
LEFT JOIN stocks stn ON
(stn.stocksIdMF = ( SELECT b.MedicalFacilitiesIdUser
FROM medicalfacilities AS b
WHERE b.MedicalFacilitiesIdUser = a.MedicalFacilitiesIdUser
ORDER BY stn.stocksId DESC LIMIT 1)
AND stn.stocksEndDate >= UNIX_TIMESTAMP() AND stn.stocksStartDate <= UNIX_TIMESTAMP())
These query I want to select one row from table stocks by conditions and with field equal value a.MedicalFacilitiesIdUser.
I get always count_stocks = 0 in result. But I need to get 1
The count(...) aggregate doesn't count null, so its argument matters:
COUNT(stn.stocksId)
Since stn is your right hand table, this will not count anything if the left join misses. You could use:
COUNT(*)
which counts every row, even if all its columns are null. Or a column from the left hand table (a) that is never null:
COUNT(a.ID)
Your subquery in the on looks very strange to me:
on stn.stocksIdMF = ( SELECT b.MedicalFacilitiesIdUser
FROM medicalfacilities AS b
WHERE b.MedicalFacilitiesIdUser = a.MedicalFacilitiesIdUser
ORDER BY stn.stocksId DESC LIMIT 1)
This is comparing MedicalFacilitiesIdUser to stocksIdMF. Admittedly, you have no sample data or data layouts, but the naming of the columns suggests that these are not the same thing. Perhaps you intend:
on stn.stocksIdMF = ( SELECT b.stocksId
-----------------------------^
FROM medicalfacilities AS b
WHERE b.MedicalFacilitiesIdUser = a.MedicalFacilitiesIdUser
ORDER BY b.stocksId DESC
LIMIT 1)
Also, ordering by stn.stocksid wouldn't do anything useful, because that would be coming from outside the subquery.
Your subquery seems redundant and main query is hard to read as much of the join statements could be placed in where clause. Additionally, original query might have a performance issue.
Recall WHERE is an implicit join and JOIN is an explicit join. Query optimizers
make no distinction between the two if they use same expressions but readability and maintainability is another thing to acknowledge.
Consider the revised version (notice I added a GROUP BY):
SELECT COUNT(stn.stocksId) AS count_stocks
FROM MedicalFacilities AS a
LEFT JOIN stocks stn ON stn.stocksIdMF = a.MedicalFacilitiesIdUser
WHERE stn.stocksEndDate >= UNIX_TIMESTAMP()
AND stn.stocksStartDate <= UNIX_TIMESTAMP()
GROUP BY stn.stocksId
ORDER BY stn.stocksId DESC
LIMIT 1

Query logic, wrong desired results mysql

SELECT * FROM
MobileApps as dtable
WHERE (SELECT COUNT(*) as c
FROM app_details
WHERE trackId=dtable.SourceID)=0
ORDER BY id ASC
LIMIT 0,2
Problem is say the first two results ordered by id are in app_details, so the COUNT(*) doesnt' equal to 0 for the first two results. But there are much more results available in MobileApps table that would equal to 0.
I supposed it would first SELECT * FROM app_details WHERE trackId=dtable.SourceID)=0 and then ORDER BY id ASC LIMIT 0,2, not the other way around, what is a possible way to get it around ?
Thanks
Your query works, but a better way to write it is:
SELECT dtable.*
FROM MobileApps dtable
LEFT JOIN app_details d ON d.trackId = dtable.SourceID
WHERE d.trackId IS NULL
ORDER BY dtable.id
LIMIT 0, 2
or:
SELECT *
From MobileApps dtable
WHERE NOT EXISTS (SELECT *
FROM app_details d
WHERE d.trackId = dtable.SourceID)
ORDER BY id
LIMIT 0, 2
See all 3 versions here: http://www.sqlfiddle.com/#!2/536db/2
For a large table, you should probably benchmark them to see which one MySQL optimizes best.

mysql random least used

I need to select a record at random but not one already selected before unless all records have been selected.
Table Setup:
_word (id, nam)
_word_tm (id, word_id, tm)
Every time a word is used it is loaded into _word_tm. What I am wanting to do is make sure I use all the words before I reuse an already used word.
What I am really looking for is something like the below but just trying to figure out how to mesh.
select w.nam FROM _word w LEFT JOIN _word_tm wt ON w.id = wt.word_id ORDER BY count(wt.id) asc, rand() limit 1
First, find out how many times the least-used words have been used:
select _word.id, count(*) c from _word
left join _word_tm on _word.id=_word_tm.word_id order by c limit 1;
Store that value (from c) in a variable $least_used. Then get all the words used that many times, in random order:
select _word.id, count(*) c from _word
left join _word_tm on _word.id=_word_tm.word_id
group by _word.id having c <= {$least_used}
order by rand() limit 1;
You should be able to do something like this:
SELECT * FROM word_table WHERE word NOT IN (SELECT word FROM words_used) ORDER BY rand() LIMIT 1;
You will need to have an updated copy of MySQL for this to work. Also, you would need to include a line of code afterward or before hand to clear/reset your words_used table once it had the same contents as word_table.
You can try the following SQL to return a random row
select A.nam
from _word A
where A.id not in (select B.id from _word_tm B)
order by rand()
limit 1
if the above does not return any reocrd , do a simple
select A.nam
from _word A
order by rand()
limit 1