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.
Related
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.
Here's my query:
SELECT a.product_title, b.product_title FROM products a, products b
WHERE b.color_id = a.color_id
AND b.price_id = a.price_id
AND b.size_id = a.size_id
AND a.id = 1
AND ??? (SELECT * FROM products LIMIT ???);
I'm trying to perform a sub query if the results of the first query is less than 10, how would I do this? Is it possible to count the rows the query gets out in the same query without performing another query?
Also is it possible to set the LIMIT to be what is required, ie. the first query gets 6 rows, I then need the limit to be 4 - to make up 10 all together.
I Really don't understand your question well,
anyway you can use variables ,
Example:
Set ACount = (select count(a.id) from products a where ...=...);
SELECT a.product_title, b.product_title FROM products a, products b
WHERE b.color_id = a.color_id
AND b.price_id = a.price_id
AND b.size_id = a.size_id
AND a.id = 1
AND if(#ACount<10, "Your where statement here",0);
You can do this using "UNION".
If you don't care about performance and just want to save one query, you can always UNION an second query and get the top 10 rows from the combined result:
SELECT * FROM (
SELECT a.product_title, b.product_title , 0 as Rank
FROM products a, products b
WHERE b.color_id = a.color_id
AND b.price_id = a.price_id
AND b.size_id = a.size_id
AND a.id = 1
LIMIT 10
UNION
SELECT product_title, '', Rank
FROM products
WHERE (your condition)
LIMIT 20
) E
ORDER BY Rank
LIMIT 10
Since the extra results from the second query will have higher rank, if you already have 10 records in the first query, there will be dropped by the limit.
Since Union will remove duplicates so you need add enough results to make sure you get at least 10.
The above code is to show you the concept and you need adjust it to suit your needs.
I have a query which does the job but instead of the trans_inventory (which is an ID of the location) I need to get the location_name.
This one is working to get the id
SELECT *
FROM {TABLE}
WHERE trans_product = 646
ORDER BY trans_date2 DESC Limit 1
But I wonder if I can do it this way, somehow embed the location table, I have tried but below doesn't work
SELECT *, site_location.location_name
FROM site_trans
cross join
(select *
From site_location)
site_location
WHERE trans_product=646 ORDER BY trans_date2 DESC Limit 1
sl.location in the JOIN must be the site_location location id field name - I used locastion_id but it might be likely id as well. I used LEFT JOIN to avoid missing site_trans in case there is no matching location id.
SELECT s.*, sl.location_name
FROM site_trans AS s
LEFT JOIN site_location AS sl ON sl.location_id = s.location_id
WHERE s.trans_product=646
ORDER BY s.trans_date2 DESC
Limit 1
I was thinking a way to using one query with a subquery instead of using two seperate queries.
But turns out using a subquery is causing multiple requests for each row in result set. Is there a way to limit that count subquery result only one with in a combined query ?
SELECT `ad_general`.`id`,
( SELECT count(`ad_general`.`id`) AS count
FROM (`ad_general`)
WHERE `city` = 708 ) AS count,
FROM (`ad_general`)
WHERE `ad_general`.`city` = '708'
ORDER BY `ad_general`.`id` DESC
LIMIT 15
May be using a join can solve the problem but dunno how ?
SELECT ad_general.id, stats.cnt
FROM ad_general
JOIN (
SELECT count(*) as cnt
FROM ad_general
WHERE city = 708
) AS stats
WHERE ad_general.city = 708
ORDER BY ad_general.id DESC
LIMIT 15;
The explicit table names aren't required, but are used both for clarity and maintainability (the explicit table names will prevent any imbiguities should the schema for ad_general or the generated table ever change).
You can self-join (join the table to itself table) and apply aggregate function to the second.
SELECT `adgen`.`id`, COUNT(`adgen_count`.`id`) AS `count`
FROM `ad_general` AS `adgen`
JOIN `ad_general` AS `adgen_count` ON `adgen_count`.city = 708
WHERE `adgen`.`city` = 708
GROUP BY `adgen`.`id`
ORDER BY `adgen`.`id` DESC
LIMIT 15
However, it's impossible to say what the appropriate grouping is without knowing the structure of the table.
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