MySQL INSERT... SELECT column count and virtual/aliased columns - mysql

I'm trying to insert using a select statement. However, I need to order the sub-select results using a ranking equation. If I create an alias, it throws off the column count. Can I somehow order my results using an equation?
INSERT INTO draft
( fk_contrib_id , end_time )
SELECT pk_contrib_id, UNIX_TIMESTAMP(), (X+Y+Z) AS ranking
FROM contrib
ORDER BY ranking DESC
LIMIT 1
I need the 'ranking' column for sorting, but if I do, the column count is off for the insert. Do I have to use two queries for this?

You could simply change your query to directly use the expression in the ORDER BY clause, like so:
INSERT INTO draft
( fk_contrib_id , end_time )
SELECT pk_contrib_id, UNIX_TIMESTAMP()
FROM contrib
ORDER BY (X+Y+Z) DESC
LIMIT 1

Remove the expression from the SELECT list. And use the expression in the ORDER BY clause.
ORDER BY X+Y+Z
It's perfectly valid to ORDER BY expressions that are not in the SELECT list.

Related

Mysql: Sort an aggregate ascending with zeros last

I'm attempting to sort an aggregate column, which contains some zero values. I need the zero values to be last.
For non-aggregate columns I can do something like this (simplified example query):
SELECT age FROM books
ORDER BY
age = 0,
age ASC
However, for aggregate columns I'm getting an error as the column doesn't exist:
SELECT avg(age) as avg_age FROM books
GROUP BY book.type
ORDER BY
avg_age = 0,
avg_age ASC
The error is:
SQLSTATE[42S22]: Column not found: 1247 Reference 'avg_age' not supported (reference to group function)
I totally appreciate why this is happening, but I wasn't able to find a workaround, any tips?
There seams to be a (old) related bug report
[21 Mar 2016 9:22] Jiří Kavalík
Description: When using alias to aggregated column in ORDER BY only
plain alias is allowed, using it in any expression returns error.
http://sqlfiddle.com/#!9/e87bb/7
Workarounds:
- select the expression and use its alias
- use a derived table and order the outer one
How to repeat: create table t(a int);
-- these work select sum(a) x from t group by a order by x; select sum(a) x from t group by a order by sum(a); select sum(a) x from t
group by a order by -sum(a);
-- this one wrongly gives "Reference 'x' not supported (reference to group function)" select sum(a) x from t group by a order by -x;
source
You would have to write, this is better as the query is then also ANSI/ISO SQL standard valid meaning the query is most likely better portable between most databases vendor software.
SELECT
avg(books.age) as avg_age
FROM books
GROUP BY books.type
ORDER BY
avg(books.age) = 0
, avg(books.age) ASC
see demo this bug is fixed in MySQL 8.0 see demo
Try repeating the code
SELECT avg(age) as avg_age
FROM books
GROUP BY book.type
ORDER BY avg(age) = 0, avg(age) ASC

Obtaining the maximum value with Order By and Limit 1

First of all, I am using MySQL. When I make the following query:
SELECT CodE,sum(tiempo) AS 'tiempo total'
FROM Participa
GROUP BY CodE
ORDER BY 'tiempo total' DESC LIMIT 1;
it shows me the first line of my table instead of the MAX value. However, If I make the following query:
SELECT CodE,sum(tiempo)
FROM Participa
GROUP BY CodE
ORDER BY 2 DESC LIMIT 1
I get the correct result.
I have just changed the alias 'tiempo total' for somthing that should be equivalent.
How it´s possible?
Only use single quotes for string and date constants -- never for column aliases. So:
SELECT CodE, sum(tiempo) AS `tiempo total`
FROM Participa
GROUP BY CodE
ORDER BY `tiempo total` DESC
LIMIT 1;
You are ordering by a constant string, not the name of a column. Hence, if you get the maximum in your query, it would be a total accident.
Note: You can get around these issues by giving columns names that never need to be escaped:
SELECT CodE, sum(tiempo) AS tiempo_total
FROM Participa
GROUP BY CodE
ORDER BY tiempo_total DESC
LIMIT 1;
Easier to type, too.

Concat 2 columns in a string, then get a count for each concatenation

I am trying to concatenate 2 columns, then count the number of rows i.e. the total number of times the merged column string exists, but I don't know if it is possible. e.g:
SELECT
CONCAT(column_1,':',column_2 ) as merged_columns,
COUNT(merged_columns)
FROM
table
GROUP BY 1
ORDER BY merged_columns DESC
Note: the colon I've inserted as a part of the string, so my result is something like 12:3. The 'count' then should tell me the number of rows that exist where column_1 =12 and column_2 = 3.
Obviously, it tells me 'merged_columns' isn't a column as it's just an alias for my CONCAT. But is this possible and if so, how?
Old question I know, but the following should work without a temp table (unless I am missing something):
SELECT
CONCAT(column_1,':',column_2 ) as merged_columns,
COUNT(CONCAT(column_1,':',column_2 ))
FROM
table
GROUP BY 1
ORDER BY merged_columns DESC
You can try creating a temp table from your concatenation select and then query that:
SELECT CONCAT(column_1,':',column_2 ) AS mergedColumns
INTO #temp
FROM table
SELECT COUNT(1) AS NumberOfRows,
mergedColumns
FROM #temp
GROUP BY mergedColumns
Hope this answer is what your are looking for.
Try this
SELECT
CONCAT(column_1,column_2 ) as merged_columns,
COUNT(*)
FROM
table
GROUP BY merged_columns
ORDER BY merged_columns DESC

MySQL sort by not sorting?

I am fetching rows from my DB using this request:
SELECT * FROM {$db_sales} WHERE date = '{$date}' ORDER BY 'amount' DESC
So, obviously, i expected the returned values to be sorted in descending order by the amount column in my DB, but it doesn't? it still fetches them, but just doesn't sort them?
Any ideas here? is my SQL statement wrong?
remove single quote around amount like this and try:
SELECT * FROM {$db_sales} WHERE date = '{$date}' ORDER BY amount DESC
Use below query
SELECT * FROM {$db_sales} WHERE date = '{$date}' ORDER BY amount DESC
ORDER BY clause uses column name.
Column name should not give in quotes.
there fore the query becomes as follows
SELECT * FROM {$db_sales} WHERE date = '{$date}' ORDER BY amount DESC

How to surface a value for more than one row in MySQL

I know that I can surface a row in a query by using it in the ORDER BY like this :
SELECT IF(`category` IS NOT NULL,`category`,"Uncategorized") AS `category` FROM `table` ORDER BY `category`="Uncategorized" DESC
Which will make the first row always contain "Uncategorized", however I have multiple rows that contain it that I also want surfaced. Here are two sample sets of returned data:
What I'm getting:
Uncategorized
Science
Health
Uncategorized
Wellness
What I want:
Uncategorized
Uncategorized
Health
Science
Wellness
I have tried a number of other things including a CASE and also using a conditional IF. What am I doing wrong?
The reason why it is not working is because the ORDER BY clause is comparing with the column name category and not on the alias given on the column.
SELECT IF(category IS NOT NULL,category,'Uncategorized') category
FROM `table`
ORDER BY IF(category IS NOT NULL,category,'Uncategorized')='Uncategorized' DESC
you can alternatively use COALESCE or IFNULL to make it shorter
SELECT COALESCE(category, 'Uncategorized') category
FROM `table`
ORDER BY COALESCE(category, 'Uncategorized') = 'Uncategorized' DESC, category
You need to use the function in the ORDER BY clause.
SELECT IF(`category` IS NOT NULL,`category`,"Uncategorized") AS `category`
FROM `table`
ORDER BY IF(`category` IS NOT NULL,`category`,"Uncategorized")="Uncategorized" DESC
You can create a custom ordering via FIELD()
...
ORDER BY FIEID(category,
'Uncategorized',
'Health',
'Science'
'Wellness')
The FIELD() function returns the index of the 1st parameter in the others.