I am trying to get my head around using GROUP_CONCAT within MYSQL.
Basically I have the following table, table1:
id, field1, field2, active
I want to bring back 5 rows within the table but in random order. So I'm using this:
SELECT GROUP_CONCAT(id ORDER BY rand()) FROM table1 WHERE active=1
This behaves as I would expect. I then want to use the output to select the other columns (field1, field2) from the table and display the results.
So I've tried using:
SELECT *
FROM table1
WHERE id IN
(
SELECT GROUP_CONCAT(id ORDER BY rand()) as id FROM table1 WHERE active=1
);
I expected something like the above to work but I cant figure out why it doesn't. It DOES bring back results but not all of them, (i.e.) my table contains 10 rows. 6 rows are set to active=1. Therefore I would expect 6 rows to be returned ... this isn't happening I may get 1,2 or 0.
Additionally if it helps I'd like to limit the number of results returned by the sub-query to 3 but adding LIMIT doesn't seem to have any affect on the results returned.
Thank you in advance for your help
I think this is what you are looking for. This will bring back 5 random active rows.
SELECT *
FROM table1
WHERE active=1
ORDER BY RAND()
LIMIT 5;
why not use this :
SELECT *, GROUP_CONCAT(id ORDER BY rand()) as randoms FROM table1 WHERE active=1
If I understand correctly, you are trying to build a query like this:
select *
from table1
where id in (1,2,3,4,5) -- Just an example
and you are trying to "fill" the in condition with a group_concat() result.
That's not the way to do it.
You only need to specify the subquery in the parenthesis:
select *
from table1
where id in (select id from table1 where active=1)
Notice some additional things:
The order by rand() is irrelevant, because the in () will be evaluated regardless of the order of the values.
In this particular scenario, I would recommend to use a join instead of in.
Using join:
select t1.*
from
table1 as t1
inner join table1 as t2 on t1.id = t2.id
where t2.active=1
Related
I have the following problem and I would like to know how to solve it creating a query on MySQL.
Check out those two tables:
I need to follow a structure to show the results I want. It is like a randon inside a randon. For example, I want to randomize each section, but ids 1 to 3 must be together and then randomize too.
How would be a query to get such results?
With this query:
select id, id_start, id_end, rand() rnd
from table2
group by id, id_start, id_end
you can return a random number for each of the rows of table2.
Join this query to table1 and sort the result first by that random number and then by random:
select t1.id, t1.description
from table1 t1
inner join (
select id, id_start, id_end, rand() rnd
from table2
group by id, id_start, id_end
) t2
on t1.id between t2.id_start and t2.id_end
order by t2.rnd, rand()
See the demo.
I am looking to run this query on a list of tables.
SELECT Description,Code,count(*) as count
FROM table1
group by Description,code
having count(*) > 1
I will have to run this query on 30+ different tables, I was wondering If I could change the from statement and just list off the table names.
In addition, is there some functionality that will add the name of the table that it came from in a seperate column to distinguish where the results came from?
Thanks in advance
You might use UNION ALL to put it together. Unless you need some dynamic table selection.
SELECT Description,Code,count(*) as count, 'table1' as tableNane
FROM table1
group by Description,code
having count(*) > 1
UNION ALL
SELECT Description,Code,count(*) as count, 'table2' as tableNane
FROM table2
group by Description,code
having count(*) > 1
...
Actualy I like #Shubhradeep Majumdar version. It will generate more concise code.
SELECT Description,Code, Count(Code), tableName FROM (
SELECT Description,Code, 'table1' as tableName
FROM table1
UNION ALL
SELECT Description,Code, 'table2' as tableName
FROM table2
) tables
GROUP BY tableName, Description, Code
HAVING COUNT(Code) > 1
But there might be a little catch to it. It is more elegant code, but it might actually be slower than first version. The problem is that tableName is appended at every record before grouping while in my first version you do that on already processed data.
Carrying over from #Marek's answer, You could first append all the tables to a table with union all.
select *, 'tab1' as tabnm from tab1
union all
select *, 'tab2' as tabnm from tab2
union all
select *, 'tab3' as tabnm from tab3
-- and so on...
And then use your code to process that final table.
will save you a great deal of time.
EDITED with a column specifying the table name
I am not very familiar with mysql and was wondering how I might rewrite the following query to fix it and speed it up. I believe I'd have to use a JOIN (or something else), but am not sure how to do this.
What I want to achieve is to perform a simple MATCH AGAINST query, and using the IDs from these results (in table2), retrieve all corresponding rows with the same IDs in table1.
SELECT *
FROM table1
WHERE id IN (
SELECT id
FROM table2
WHERE MATCH (gloss) AGAINST ('example' IN BOOLEAN MODE)
LIMIT 10
)
Note that I'm aware the subquery above doesn't work with a LIMIT.
Thank you for your time.
try a simple inner join
SELECT *
FROM table1
INNER JOIN table2
USING(id)
WHERE MATCH (gloss) AGAINST ('example' IN BOOLEAN MODE)
LIMIT 10
to run your IN with a LIMIT you have to wrap it inside another query like this
SELECT *
FROM table1
WHERE id IN (SELECT id FROM
(SELECT id
FROM table2
WHERE MATCH (gloss) AGAINST ('example' IN BOOLEAN MODE)
LIMIT 10
)T1
)
to get exact same result as your IN with LIMIT 10 using INNER JOIN you can do this
SELECT *
FROM table1
INNER JOIN
(SELECT id
FROM table2
WHERE MATCH (gloss) AGAINST ('example' IN BOOLEAN MODE)
LIMIT 10
)T1
USING (id)
Try adding the index on the id column of the table as
ALTER TABLE TABLE_NAME ADD INDEX (COLUMN_NAME);
This will definitely increase the performance of the query...
Hope this helps... :)
Assuming table1 and table2 both have a large number of rows (ie several hundred thousand), is the following an inefficient query?
Edit: Order by field added.
SELECT * FROM (
SELECT title, updated FROM table1
UNION
SELECT title, updated FROM table2
) AS query
ORDER BY updated DESC
LIMIT 25
If you absolutely need distinct results, another possibility is to use union all and a group by clause instead:
SELECT title FROM (
SELECT title FROM table1 group by title
UNION ALL
SELECT title FROM table2 group by title
) AS query
group by title
LIMIT 25;
Testing this without the limit clause on an indexed ID column from two tables with ~920K rows each in a test database (at $work) resulted in a bit over a second with the query above and about 17 seconds via a union.
this should be even faster - but then I see no ORDER BY so what 25 records do you actually want?
SELECT * FROM (
SELECT title FROM table1 LIMIT 25
UNION
SELECT title FROM table2 LIMIT 25
) AS query
LIMIT 25
UNION must make an extra pass to fetch the distinct records, so you should use UNION ALL.
Yes, use order by and limits in the inner queries.
SELECT * FROM (
(SELECT title FROM table1 ORDER BY title ASC LIMIT C)
UNION
(SELECT title FROM table2 ORDER BY title ASC LIMIT C)
) AS query
LIMIT 25
This will only go through C rows instead of N (hundreds of thousands). The ORDER BY is necessary and should be on an indexed column.
C is a heuristic constant that should be tuned according to the domain. If you only expect a few duplicates, C=50-100 is probably ok.
You can also find out this for yourself by using EXPLAIN.
I'am trying to understand what causes the following, maybe you could help me:
I have a query like:
select field1,fieldDate from table1
union all
select field1,fieldDate from table2
order by fieldDate desc
and the another one like this:
select field1,field2,fieldDate from table1
union all
select field1,field2,fieldDate from table2
order by fieldDate desc
So basically they are the same with the exception that in the second I retrieve an extra field.
Now, both results come with a diferent ordering, but just for the cases that the dates are exacly the same. For example there are 2 rows (row1,row2) with date 2009-11-25 09:41:55. For query 1 row1 comes before row2 and for query 2 row2 comes before row1.
Does somebody knows why this happens?
Thanks,
Regards
The ordering based on any fields that you don't explicitly order by is undefined, and the optimizer can change the ordering if it thinks that results in a better execution plan. Given two rows with the exact same value in the order by field you can not depend on them being in any particularly order in relation to each other unless you explicitly order by another field with different values.
Can you do this
select * from ( select
field1,field2,fieldDate, 0 as ordercol from table1
union all select
field1,field2,fieldDate, 1 as ordercol from table2) t1
order by fieldDate desc, ordercol asc
Straight from the MySQl manual, to user order by on a union you have to parenthesis the individual tables.
(select field1,fieldDate from table1)
union all
(select field1,fieldDate from table2)
order by fieldDate desc
This is not SQL standards compliant! The code you entered should order the union of both tables but to my surprise MySQL has the above syntax.
The order in which rows with the same fieldDate are returned can differ for each query execution. Usually this order will be the same but you should not count on it. If you want any extra ordering state more order by fields.
EDIT: This answer is wrong: the order by works on the entire union. I'll leave it here to save others the trouble :)
Your order by only works on the second part of the union. You can use a subquery to make the order by work on the entire union:
select field1,field2,fieldDate
from (
select field1,field2,fieldDate
from table1
union all
select field1,field2,fieldDate
from table2
) SubQueryName
order by fieldDate desc