mysql keep position of query with union statement - mysql - mysql

1. select something, date_something from my_table
where [conditions]
union
2. select something, date_something from my_table
where [conditions]
union
3. select something, date_something from my_table
where [conditions]
This pseudo-code at least in my workbench returns me the exact result I need. I didn't use the ORDER BY keyword at the end, which I always do, because applying will destroy the order obviously.
Is there a way to assure the query would return data in the following order? For me it is really important I could fix the order by 1,2,3 "partitions", rather than applying it overvalues. I hope you understand.
Any ideas would be welcomed.

You should be able to add a field to do that, e.g.:
select 1 as Partition, something, date_something
from my_table
where [conditions]
union
select 2 as Partition, something, date_something
from my_table
where [conditions]
union
select 3 as Partition, something, date_something
from my_table
where [conditions]
order by Partition

Related

How to use ORDER BY inside UNION

I want to use ORDER BY on every UNION ALL queries, but I can't figure out the right syntax. This is what I want:
(
SELECT id, user_id, other_id, name
FROM tablename
WHERE user_id = 123 AND user_in IN (...)
ORDER BY name
)
UNION ALL
(
SELECT id, user_id, other_id, name
FROM tablename
WHERE user_id = 456 AND user_id NOT IN (...)
ORDER BY name
)
EDIT:
Just to be clear: I need two ordered lists like this, not one:
1
2
3
1
2
3
4
5
Thank you very much!
Something like this should work in MySQL:
SELECT a.*
FROM (
SELECT ... FROM ... ORDER BY ...
) a
UNION ALL
SELECT b.*
FROM (
SELECT ... FROM ... ORDER BY ...
) b
to return rows in an order we'd like them returned. i.e. MySQL seems to honor the ORDER BY clauses inside the inline views.
But, without an ORDER BY clause on the outermost query, the order that the rows are returned is not guaranteed.
If we need the rows returned in a particular sequence, we can include an ORDER BY on the outermost query. In a lot of use cases, we can just use an ORDER BY on the outermost query to satisfy the results.
But when we have a use case where we need all the rows from the first query returned before all the rows from the second query, one option is to include an extra discriminator column in each of the queries. For example, add ,'a' AS src in the first query, ,'b' AS src to the second query.
Then the outermost query could include ORDER BY src, name, to guarantee the sequence of the results.
FOLLOWUP
In your original query, the ORDER BY in your queries is discarded by the optimizer; since there is no ORDER BY applied to the outer query, MySQL is free to return the rows in whatever order it wants.
The "trick" in query in my answer (above) is dependent on behavior that may be specific to some versions of MySQL.
Test case:
populate tables
CREATE TABLE foo2 (id INT PRIMARY KEY, role VARCHAR(20)) ENGINE=InnoDB;
CREATE TABLE foo3 (id INT PRIMARY KEY, role VARCHAR(20)) ENGINE=InnoDB;
INSERT INTO foo2 (id, role) VALUES
(1,'sam'),(2,'frodo'),(3,'aragorn'),(4,'pippin'),(5,'gandalf');
INSERT INTO foo3 (id, role) VALUES
(1,'gimli'),(2,'boromir'),(3,'elron'),(4,'merry'),(5,'legolas');
query
SELECT a.*
FROM ( SELECT s.id, s.role
FROM foo2 s
ORDER BY s.role
) a
UNION ALL
SELECT b.*
FROM ( SELECT t.id, t.role
FROM foo3 t
ORDER BY t.role
) b
resultset returned
id role
------ ---------
3 aragorn
2 frodo
5 gandalf
4 pippin
1 sam
2 boromir
3 elron
1 gimli
5 legolas
4 merry
The rows from foo2 are returned "in order", followed by the rows from foo3, again, "in order".
Note (again) that this behavior is NOT guaranteed. (The behavior we observer is a side effect of how MySQL processes inline views (derived tables). This behavior may be different in versions after 5.5.)
If you need the rows returned in a particular order, then specify an ORDER BY clause for the outermost query. And that ordering will apply to the entire resultset.
As I mentioned earlier, if I needed the rows from the first query first, followed by the second query, I would include a "discriminator" column in each query, and then include the "discriminator" column in the ORDER BY clause. I would also do away with the inline views, and do something like this:
SELECT s.id, s.role, 's' AS src
FROM foo2 s
UNION ALL
SELECT t.id, t.role, 't' AS src
FROM foo3 t
ORDER BY src, role
Don't use ORDER BY in an individual SELECT statement inside a UNION, unless you're using LIMIT with it.
The MySQL docs on UNION explain why (emphasis mine):
To apply ORDER BY or LIMIT to an individual SELECT, place the clause
inside the parentheses that enclose the SELECT:
(SELECT a FROM t1 WHERE a=10 AND B=1 ORDER BY a LIMIT 10) UNION
(SELECT a FROM t2 WHERE a=11 AND B=2 ORDER BY a LIMIT 10);
However, use of ORDER BY for individual SELECT statements implies
nothing about the order in which the rows appear in the final result
because UNION by default produces an unordered set of rows. Therefore,
the use of ORDER BY in this context is typically in conjunction with
LIMIT, so that it is used to determine the subset of the selected rows
to retrieve for the SELECT, even though it does not necessarily affect
the order of those rows in the final UNION result. If ORDER BY appears
without LIMIT in a SELECT, it is optimized away because it will have
no effect anyway.
To use an ORDER BY or LIMIT clause to sort or limit the entire UNION
result, parenthesize the individual SELECT statements and place the
ORDER BY or LIMIT after the last one. The following example uses both
clauses:
(SELECT a FROM t1 WHERE a=10 AND B=1)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2)
ORDER BY a LIMIT 10;
It seems like an ORDER BY clause like the following will get you what you want:
ORDER BY user_id, name
You just use one ORDER BY at the very end.
The Union turns two selects into one logical select. The order-by applies to the entire set, not to each part.
Don't use any parens either. Just:
SELECT 1 as Origin, blah blah FROM foo WHERE x
UNION ALL
SELECT 2 as Origin, blah blah FROM foo WHERE y
ORDER BY Origin, z
(SELECT id, user_id, other_id, name
FROM tablename
WHERE user_id = 123
AND user_in IN (...))
UNION ALL
(SELECT id, user_id, other_id, name
FROM tablename
WHERE user_id = 456
AND user_id NOT IN (...)))
ORDER BY name
You can also simplify this query:
SELECT id, user_id, other_id, name
FROM tablename
WHERE (user_id = 123 AND user_in IN (...))
OR (user_id = 456 AND user_id NOT IN (...))

SQL - ORDER BY ASC LIMIT 1 excludes multiple same results - best method?

I'm still learning SQL so I was wondering if there is a better way of doing the following.
I need to get row data for the lowest and highest values in a column (lets call it columnA).
I would use:
SELECT *
FROM table
ORDER BY columnA
DESC LIMIT 1
Problem is I get only one result due to the LIMIT 1 but there may be identical lowest / highest values in ColumnA that have different values in the other columns. I need those other rows too.
There is SELECT(MAX) but I believe that will also only produce one row of data.
The ways I can think do this are by putting the highest / lowest columnA values into a variable and then back into a second query OR use a LEFT JOIN on alias tables to do this in single query but is there any more direct method?
The simplest way is to perform a sub-query:
SELECT * FROM MyTable WHERE columnA = (SELECT MAX(columnA) FROM MyTable);
You can even query both extremes at once:
SELECT * FROM MyTable
WHERE columnA = (SELECT MAX(columnA) FROM MyTable);
OR columnA = (SELECT MIN(columnA) FROM MyTable);
I haven't tested the next one (don't know if MySQL supports UNION in
sub-queries), but it should work as well, might be a bit more
efficient (depending on your data size).
SELECT * FROM MyTable
WHERE columnA IN (
SELECT MAX(columnA) FROM MyTable
UNION
SELECT MIN(columnA) FROM MyTable
);
Another option is :
SELECT *
FROM MyTable m1
WHERE not exists (select 1 from MyTable where columnA > m1.columnA)

MySQL: Counting column from different tables on a certain timeframe

I have the following query:
SELECT SUM(COUNTED) AS TCOUNTED
FROM (SELECT COUNTED FROM `clicks`.`t1`
UNION ALL
SELECT COUNTED FROM `clicks`.`t2`
UNION ALL
SELECT COUNTED FROM `clicks`.`t3`
) AS TMP
Where and how do I add a time constraint? I want it to count only between certain dates... Sorry for the MySQL noobness.
Thanks!
SELECT SUM(COUNTED) AS TCOUNTED
FROM (SELECT COUNTED FROM `clicks`.`t1` WHERE somedatecol BETWEEN somedate AND somedate
UNION ALL
SELECT COUNTED FROM `clicks`.`t2` WHERE somedatecol BETWEEN somedate AND somedate
UNION ALL
SELECT COUNTED FROM `clicks`.`t3` WHERE somedatecol BETWEEN somedate AND somedate
) AS TMP`
http://dev.mysql.com/doc/refman/5.0/en/select.html
I would think your best bet is to include the where clause inside each sub-select before the UNION statements.
SELECT SUM(COUNTED) AS TCOUNTED FROM
(SELECT COUNTED FROM clicks.t1 WHERE <fieldname> BETWEEN '<date1>' AND '<date2>'
UNION ALL
SELECT COUNTED FROM clicks.t2 WHERE <fieldname> BETWEEN '<date1>' AND '<date2>'
UNION ALL
SELECT COUNTED FROM clicks.t3 WHERE <fieldname> BETWEEN '<date1>' AND '<date2>')
AS TMP;
Of course it as all relative to what you are trying to accomplish with the query.

How to select sum across 100 tables?

I unfortunately have spread some data across about 100 tables, and I don't have time to reorganize it, so I am curious as to how I might do a select sum(column_name) across that many tables.
I have found examples of how to sum across 2 tables, but never an example of 100.
Anybody know how?
Addendum: Using a very large command has resulted in a "memory exhausted" error. Is there a way to do this using LIKE ?
I would say the easiest way to do this is to do lots of selects (one for each table) of the value you want to sum and just do a sum on the union of that?
Something like :
SELECT SUM(VALUE) FROM (
select 1 VALUE
UNION
select 2 VALUE
UNION
select 3 VALUE) as DATA
Of course the selects will be selecting a column from each table and not just an integer like this, but you get the idea ...
You seem fixated on LIKE, but LIKE is for WHERE clauses, not choosing tables to select from. If selecting from all the tables at once is too much for your system to handle, the obvious solution is to query each table individually and then add up the results using a perl/php/other script.
You can do something like this:
select sum(sumcol) FROM (
select sum(col) as sumcol from table1
union all
select sum(col) as sumcol from table2
union all
select sum(col) as sumcol from table3
...
union all
select sum(col) as sumcol from table100
);
This is done with much less memory consumption when you sum-up in union parts, too.
It would be a big query, but something like this would do it:
SELECT SUM(col) FROM (
SELECT col FROM table1
UNION ALL
SELECT col FROM table2
UNION ALL
SELECT col FROM table3
...
SELECT col FROM table100
) a

mysql sum question

Is it possible to get the sum of a column and all the column itself using one query?
I mean, I need SUM(Result.num) and the individual Result.num as well, but I dont want to use two separate queries for the purpose? the idea result might be the SUM as another column in the result.
Result might look like:
col1
Result.num1, SUM
Result.num2, SUM
Result.num3, SUM
....
SELECT SUM(Result.num)
FROM (SELECT COUNT(colA) AS num
FROM Table1
GROUP BY colB) AS Result;
SELECT Result.num
FROM (SELECT COUNT(colA) AS num
FROM Table1
GROUP BY colB) AS Result;
The answer is that you will do two statements but you can return the results in one result set. You can do that with a UNION ALL statement. Just take your two queries and put a UNION ALL statement between them. It will look like this:
SELECT Result.num
FROM (SELECT COUNT(colA) AS num
FROM Table1
GROUP BY colB) AS Result;
UNION ALL
SELECT SUM(Result.num)
FROM (SELECT COUNT(colA) AS num
FROM Table1
GROUP BY colB) AS Result;
I switched the order around so that your SUM value would be at the end but you could put it at the beginning if you would like.
Pretty sure you just need to union your queries
SELECT SUM(Result.num) FROM (SELECT COUNT(colA) AS num FROM Table1 group by colB) AS Result
union all
SELECT Result.num FROM (SELECT COUNT(colA) AS num FROM Table1 group by colB) AS Result;
The WITH ROLLUP clause might be useful to you here.
http://dev.mysql.com/doc/refman/5.0/en/group-by-modifiers.html