two slightly different queries into one - use a conditional var? - mysql

Instead of executing 2 slightly different sql statements to get a total of 10 results can it be done with just one select?
e.g
select
a
, b
, c
from mytable limit 3
select
a
, b
, LEFT(100, c )
from mytable limit 3, 10

Check out UNION syntax
(SELECT a,b,c FROM mytable LIMIT 3)
UNION
(SELECT a,b,LEFT(100, c) FROM mytable LIMIT 3, 10);
Note the parentheses - these ensure the final LIMIT clause applies to the second query and not the whole result set.
Unless you've got a numeric key in the result which would let you use an IF to format the first n results differently, I don't think you're going to do this with a single select.

You can select all ten rows and then use a case statement to control what value is returned depending on a conditional statement you define.
set #line_total= 0;
select
a,
b,
#line_total := #line_total + 1,
(case when #line_total < 4
then c
else left(100, c) end)
from test_query limit 10;
http://dev.mysql.com/doc/refman/5.0/en/case-statement.html

Related

How to "short circuit"/conditionally add run union clause in a mysql query?

I am selecting some rows from different tables
The logic is like this:
I want to return in total only 10 results, I try first table_a and if I cannot fetch 10 rows from table_a I fill the remaining rows from the results fetched from table_b
Pseudo-query
select value from table_a limit 10
union # ONLY IF COULD NOT FETCH 10 values from table_a
(select value from table_b limit 10)
limit 10
Is something like this possible in mysql and if yes how ?
Some simple test cases
test case 1: that if I can fetch 10 rows form table_a don't want to execute the union as I have enough results.
test case 2: I got 4 values(rows) from table_a then union executes and I get N more rows from table_b, in total should never get more than 10 rows (limit 10)
test case 3:
0 items in table_a, the query will only return up to at most 10 items from table_b
PS:
I am aware and know how to solve this via the programming language.
In that case would be as easy as:
$queryA = 'select value from table_a limit 10';
$results = $sql->execute($queryA);
if (count($results) < 10) {
$queryB = sprint('select value from table_b limit %d', 10 - count($results));
$resultsB = $sql->execute($queryB);
$results = $results + $resultsB;
}
I wonder if can be done in a more elegant minimal way directly from mysql
You can have a dummy column to count the rows from table_a and then can use a sub-query to have your desired result -
SELECT value
FROM (SELECT 1 as src, value
FROM table_a
UNION
SELECT 2 as src, value
FROM table_b
ORDER BY src
LIMIT 10
) x;

MySQL one query grouped by n rows, max and min inside group, possible?

I think there is no question like this.
I need to group rows by n records and get some values of this group.
I think is better to explain with a graphic example:
Is possible to do a query like this? if not my solution will be make an script to create another table with this but I donĀ“t like duplicate data at all.
Thanks!!!
set #counter=-1;
select xgroup,max(x) as mx, max(y) as my, avg(value3) as v3,
from
(
select (#counter := #counter +1) as counter,
#counter div 5 as xgroup,
currency, datetime, value1, value2,
case mod(#counter,5) when 0 then value1 else 00 end as x,
case mod(#counter,5) when 4 then value2 else 00 end as y,
mod(#counter,5) as xxx
FROM findata
) name1
group by xgroup;
#jms has the right approach, but you have to be very careful when using variables:
You should not assign a variable in one expression and then reference it in another in the same select.
To work in the most recent versions of MySQL, I would suggest ordering the data in a subquery.
In addition, there are some other values that you need:
select min(col1), min(col2),
max(case when mod(rn, 5) = 0 then col3 end),
max(col4), min(col5),
max(case when mod(rn, 5) or rn = #rn then col6 end),
max(case when mod(rn, 5) or rn = #rn then col7 end)
from (select (#rn := #rn + 1) as rn, t.*
from (select t.*
from t
order by col1, col2
) t cross join
(select #rn := -1) params
) t
group by (#rn div 5);
Note the logic is a bit arcane for the last values -- this is to take into account the final group that might not have exactly 5 rows.
You need a column that looks like(assuming you want to group every 5 rows)
dummy_table
1
1
1
1
1
2
2
2
2
2
...
You can do this by using generate_series() if you are using postgre sql by using
select t1 from (select generate_series(1,x)) t1, (select generate_series(1,5)) t2;
where you can replace x by (total rows/5) i.e. for 100 rows, x = 20. If you are using any other SQL platform, you can just work on creating this dummy table accordingly.
Once you get this dummy_table, join it with your table on row_number of your table with t1 column of dummy_table(not row_number of dummy_table). Syntax for accessing row number should be straightforward.
After the join, group by this t1 column and do the required aggregation. To do this in a single query, you can do the above in an inner query and do aggregation outside it. Hope this makes sense.
Ok, thanks you all guys for your answers, thanks to it I found the simple solution.
I simply add an autoincrement column, and then I can group results by integer division by 5.
And with this query:
SELECT id,
symbol,
datetime,
open,
MAX(high),
MIN(low),
SUBSTRING_INDEX( GROUP_CONCAT(CAST(close AS CHAR) ORDER BY datetime DESC), ',', 1 ) AS close
FROM `table`
GROUP BY (id-1) DIV 5
And the resulting is:
Thanks!
A solution is to introduce some field for grouping rows for aggregative operations.
It can be reached by introducing a user-variable and assigning values that will allow to group rows as required. For example, it can be a row counter divided by grouping chuck size and rounded to nearest upper ceil number:
SET #counter=0;
SELECT CEIL((#counter:=#counter+1)/5) AS chunk, MAX(high), MIN(low) FROM `table` GROUP BY chunk;

How to get all used values in columns in mysql?

I have a MySQL table with columns and values like this:
Column "A": 1, 5, 3, 2, 3, 1, 4, 5, ...
Column "B": 11, 15, 10, 12, 13, 14, 15, 10, 11, ...
Column "C": .... etc.
There is multiple columns in table with repeating numeric values.
I want to find out unique values in each column. So for column "A" it would return 1,2,3,4,5.
Currently I am using this query for one column:
SELECT concat(A) FROM table GROUP BY A;
But I don't know how to do it for multiple columns
If it's a small enough set of values, you can use the GROUP_CONCAT aggregate function, with the DISTINCT keyword
For example:
SELECT GROUP_CONCAT(DISTINCT a ORDER BY a) AS a_values
, GROUP_CONCAT(DISTINCT b ORDER BY b) AS b_values
, GROUP_CONCAT(DISTINCT c ORDER BY c) AS c_values
FROM mytable
The length of the string returned by GROUP_CONCAT is limited by the max_group_concat_len variable (it's in the reference) and I think the max_allowed_packet also comes into play.
Compare the length of the string returned to max_group_concat_len to see if it's shorter, to know that the return string hasn't been silently truncated.
If you want to combine all of those values together, into a single distinct list, you could do something like this:
SELECT GROUP_CONCAT(DISTINCT val ORDER BY val) AS col_values
FROM ( SELECT a AS val FROM mytable
UNION
SELECT b FROM mytable
UNION
SELECT c FROM mytable
) v
EDIT
I was confused by the use of the CONCAT function in the query, and misread the specification. The queries above return a single row, and returns a result that looks EXACTLY like what OP specified:
1,2,3,4,5,...
If we want to return each value on a separate row, a result that looks like this:
val
---
1
2
3
4
5
Then the query from Tim3880's answer does that, but the outer query isn't really necessary.
I'd want to add an ORDER BY, and actually write the query like this:
(SELECT a AS val FROM mytable)
UNION
(SELECT b AS val FROM mytable)
UNION
(SELECT c AS val FROM mytable)
ORDER BY 1
EDIT
Added SQL Fiddle showing how I interpret the specification (table, columns, exemplar values), and results from SQL statements above... one statement returning distinct values as individual rows (query immediately above), and a statement returning a comma separated list (the first query in my answer.)
SQL Fiddle Example HERE http://sqlfiddle.com/#!9/3d61c/1
If we want to identify which column(s) a value appears in
SELECT v.val
, GROUP_CONCAT(DISTINCT v.col ORDER BY v.col) AS in_cols
, MAX(v.col='a') AS in_col_a
, MAX(v.col='b') AS in_col_b
, MAX(v.col='c') AS in_col_c
FROM (
SELECT a AS val, 'a' AS col FROM mytable
UNION
SELECT b AS val, 'b' AS col FROM mytable
UNION
SELECT c AS val, 'c' AS col FROM mytable
) v
GROUP BY v.val
ORDER BY v.val
If your query works for A, then you can do it for A, B, C using this:
SELECT A FROM
(
SELECT A FROM table
UNION
SELECT B FROM table
UNION
SELECT C FROM table
) e
as long as the three columns have compatible types.

SQL Lower Bound?

I would like to write a sql query that returns all values greater than or equal to x and also the first value that is not greater than x.
For example if we have a table containing values 1, 2, 3, 4, 5 and x is 3, I need to return 2, 3, 4, 5.
The fact that my example includes evenly spaced integers does not help because my actual data is not as cooperative.
Is this even possible or am I better off just getting the entire table and manually figuring out which rows I need?
SELECT <columns> -- you want in the result
FROM tableX
WHERE columnX >=
( SELECT MAX(columnX)
FROM tableX
WHERE columnX < #x -- #x is the parameter, 3 in your example
) ;
union is your best bet. paste together the set of all values greater than x, and the largest value less than x. Something like the following should work:
SELECT n FROM table WHERE n > $x ORDER BY n DESC
UNION SELECT n from table WHERE n < $x ORDER By n DESC LIMIT 0,1;
SELECT * FROM MyTable WHERE MyColumn >= 3
UNION
SELECT * FROM MyTable WHERE MyColumn < 3 ORDER BY MyColumn DESC LIMIT 1

MySQL, SELECT * FROM t WHERE c={The most duplicated entry}

Pretty much as the title says, that was the simplest way I could explain it. To elaborate...
I first need to find the value of column c that has been duplicated the most times (mostDuplicated), and then SELECT * FROM t WHERE c=mostDuplicated
To go on about it further...
Here's my data:
SELECT * FROM t
a, b, c
- - -
1, 1, 1
2, 2, 1
3, 3, 1
4, 4, 2
5, 5, 3
So ignore the values in columns a & b completely, just concentrate on column c. I need to find the most duplicated value in column c (which is 1), and then SELECT only these records WHERE c=1. I want to do this in a single query if possible.
Do a "group by" query to count the number of unique values of c, order it descending and select only the top row. Then use the output as a subquery to select rows with that particular value of c:
SELECT * FROM t WHERE c = (SELECT c FROM t GROUP BY c ORDER BY COUNT(*) DESC LIMIT 1)
SELECT c FROM t GROUP BY c ORDER BY count(*) DESC LIMIT 1
Well it will be, like this:
SELECT * FROM t WHERE c =
(SELECT c FROM
(SELECT c, count(c) as co
FROM t ORDER BY co DESC LIMIT 1))
Hope this help
Here you go, it's a bit convoluted:
SELECT
*
FROM
t
WHERE
(
c IN
(
SELECT c
FROM (
SELECT
c,
COUNT(c) as freq
FROM
t
GROUP BY
c
ORDER BY
freq DESC,
c ASC
LIMIT 1
) AS t2
)
)
Basically, it's going this:
1. determine how often each value of C is repeated
2. select the value of the MAXimum repeats
3. use that value to determine what value of C to use when select * from the entire table.