I am using MySQL database. I have to make a stored procedure which accepts an integer type parameter. Depending upon the integer's value i have to 'order by' a different value like this..
**if(type == 1) than
order by Date Desc,
Quantity asc,
Amount asc
else if(type == 2)than
order by Date ASc,
Quantity asc,
Amount asc
else if(type == 3)than
order by
Quantity asc
Date desc,
Amount asc
However when i try this i am unable to do this its gives error also.
If you look at the syntax for SELECT, you'll see that the ORDER BY clause can't appear within a CASE statement.
If a column is a numeric type, you can write an expression that is 1 for ascending, -1 for descending and multiply the expression by the column to sort by, though this will impact performance as MySQL won't be able to use any indices for the sort.
SELECT ...
ORDER BY IF(?='d', -1, 1) * value
In general however, you'll have to use different statements to get different orderings.
If Date is a proper date or datetime you can do something like this:
ORDER BY
CASE type WHEN 3 THEN -1 * Date ELSE Date END asc,
Quantity asc, Amount asc
http://dev.mysql.com/doc/refman/5.0/en/case-statement.html
This works because date, time and the other MySQL date and time types are stored internally as integers:
http://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html
Well i got the solution finally....
SELECT distinct
order_detail.*, -(1)*CAST(order_detail.Date as unsigned) as lOrderDate,
from order_detail
order by
CASE
WHEN type = 1 THEN lOrderDate
WHEN type = 2 THEN order_detail.Date
WHEN type = 3 THEN order_detail.Quantity
END,
CASE
WHEN type = 1 THEN order_detail.Quantity
WHEN type = 2 THEN order_detail.Quantity
WHEN type = 3 THEN lOrderDate
END,
CASE
WHEN type = 1 THEN order_detail.Amount
WHEN type = 2 THEN order_detail.Amount
WHEN type = 3 THEN order_detail.Amount
END;
Two ways:
Build your query - like a string, then use a prepared statements to execute it.
Use IF-ELSEIF-END IF statement to execute three different SELECT queries.
Related
I have a MySQL script to find out the newest record, but it fails to get the incorrect result. I am giving the SQL script below:
SELECT
adjust_after,
spu_code,
sku_code,
store_id,
create_time
FROM
goods_store_stock_update_record
WHERE
is_del = 0
AND create_time >= DATE '2021-05-26'
AND create_time <= DATE '2021-05-27'
AND store_id = '18cc1cc715774d0196d17420c5104c15'
AND sku_code = 'SKUH201900001202050004' HAVING MAX(create_time)
There is a result without Having max(create_time):
"adjust_after" "spu_code" "sku_code" "store_id" "create_time"
"8" "SPH201900001202050001" "SKUH201900001202050004" "18cc1cc715774d0196d17420c5104c15" "26/5/2021 11:29:20"
"7" "SPH201900001202050001" "SKUH201900001202050004" "18cc1cc715774d0196d17420c5104c15" "26/5/2021 11:35:14"
But, when I am trying to query the create_time that was the newest:2021-05-26 11:35:14 record using having max(create_time). Unfortunately, It returns the incorrect record below:
8 SPH201900001202050001 SKUH201900001202050004 18cc1cc715774d0196d17420c5104c15 2021-05-26 11:29:20
Therefore, in this situation, how can I correct the querying script without using order by create_time and limit one.
Best regards. I really appreciate it.
There are two main mistakes in your query.
First, HAVING wants a boolean expression, just like WHERE. MAX(create_time) is not a boolean, but a datetime. What MySQL does here is convert the datetime to a number (maybe the internal representation of that datetime) and the number to a boolean (where 0 = false and everything else = true). So, that expression will result in true for about every row.
Second, MAX(create_time) is an aggregation. Without a GROUP BYclause this results in a single row. adjust_after etc. however, are not aggregated. This should result in a syntax error, but MySQL applies ANY_VALUE instead. This means you are telling MySQL, to give you one of the adjust_after that it finds, one of the spu_code, etc., all arbitrarily picked.
The straight-forward solution would be ORDER BY create_time LIMIT 1, which you don't want for reasons unknown to us.
Another solution is
SELECT
adjust_after,
spu_code,
sku_code,
store_id,
create_time
FROM goods_store_stock_update_record
WHERE is_del = 0
AND store_id = '18cc1cc715774d0196d17420c5104c15'
AND sku_code = 'SKUH201900001202050004' HAVING MAX(create_time)
AND create_time =
(
SELECT MAX(create_time)
FROM goods_store_stock_update_record
WHERE is_del = 0
AND create_time >= DATE '2021-05-26'
AND create_time <= DATE '2021-05-27'
AND store_id = '18cc1cc715774d0196d17420c5104c15'
AND sku_code = 'SKUH201900001202050004'
);
I have a table with several rows of timestamp (unix epoch)
eg: 1620518277 , 1556748676 , 1547547076, 1602756807, 944971077 (field name -> date_stamp)
And by using
SELECT *
FROM table
ORDER BY date_stamp DESC
The result of this query is :
1. 944971077
2. 1620518277
3. 1602756807
4. 1556748676
5. 1547547076
Everything is sorted fine but how can 944971077 > 1620518277 ???
Anybody had this kind of strange SQL issues ?
Presumably, you are storing these timestamps as strings, not as numbers. A simple option forces a numeric conversion:
SELECT * FROM table ORDER BY date_stamp + 0 DESC
This would occur if timestamp were a string. A simple method is to convert to a number using implicit conversion:
SELECT *
FROM table
ORDER BY date_stamp + 0 DESC
Ok I am lost, I have no idea why those both querys have different output.
The table looks something like this:
+------------+--------+--------+
| date | kills | deaths |
+------------+--------+--------+
| 2016-05-03 | 123456 | 123456 |
+------------+--------+--------+
SELECT SUBDATE(CURRENT_DATE(),30), `kills`, `deaths`
FROM `bf4c_1558544842`
WHERE `date` <= SUBDATE(CURRENT_DATE(),30)
ORDER BY `date` DESC
LIMIT 1
SELECT SUBDATE(CURRENT_DATE(),30) AS "date", `kills`, `deaths`
FROM `bf4c_1558544842`
WHERE `date` <= SUBDATE(CURRENT_DATE(),30)
ORDER BY `date` DESC
LIMIT 1
The only difference is the AS "date", but why does that change the selection ?
The first gets me the intended first after the given border and the second gives me the last in the table.
Could pleas someone explain me why this happens ?
Thanks in advance, Feirell.
On the second query the expression SUBDATE(CURRENT_DATE(),30) is aliased as date. Later on, the selected rows are ORDER BY date and after the sort only the first row is returned.
The documentation of the SELECT statement explains:
A select_expr can be given an alias using AS alias_name. The alias is used as the expression's column name and can be used in GROUP BY, ORDER BY, or HAVING clauses.
...
MySQL resolves unqualified column or alias references in ORDER BY clauses by searching in the select_expr values, then in the columns of the tables in the FROM clause.
This basically means that aliases have higher priority than column names.
There is a column named date in the table. In the first query, ORDER BY date uses it for sorting and you get the results you expect.
On the second query, the date alias is used by the SORT BY date clause. But since it aliases the constant expression SUBDATE(CURRENT_DATE(),30) all the selected rows have the same value for the date expression. They are already sorted, no matter what their order is. Any result is possible in this case.
Edit:
A solution would be to add the table name in front of the date in the order by clause like this:
SELECT SUBDATE(CURRENT_DATE(),30) AS "date", `kills`, `deaths`
FROM `bf4c_1558544842`
WHERE `date` <= SUBDATE(CURRENT_DATE(),30)
ORDER BY `bf4c_1558544842`.`date` DESC
LIMIT 1
This way the interpreter knows that the column is meant not the new alias.
Firstly, I apologize for the poor question title, I can't quite explain what my problem is, but I'm sure that an experienced MySQL user will know.
After querying the database to retrieve a specific set of customers, they are originally sorted by the "completed" column, with values of "0" and "1".
I would like to sort all customers with the value "0" by delivery date ASC and, all customers with the value "1" by delivery date DESC.
Here is my first and only failed attempt:
mysql_query("SELECT * FROM users WHERE (completed='0' ORDER BY delivery ASC) AND (completed='1' ORDER BY delivery DESC)") or die(mysql_error());
This could be done using case-when in the order by clause as
SELECT * FROM users
order by
case
when completed='0' then delivery
end,
case
when completed='1' then delivery
end desc;
If you need to send all completed='0' on the top assuming there is no null values then you can do as
order by
completed,
case
when completed='0' then delivery
end,
case
when completed='1' then delivery
end desc;
The first sorting field is completed ASC-ending, of course.
For the second field you can use an expression that makes the values of delivered to be sorted as desired. Assuming the type of column delivered is DATE or DATETIME, UNIX_TIMESTAMP(delivered) is a number.
For completed = '0' use UNIX_TIMESTAMP(delivered) in the ascending order. For completed <> '0' using the negated value (- UNIX_TIMESTAMP(delivered)) also sorted ASC-ending will reverse the order of the rows.
This is the query:
SELECT *
FROM users
ORDER BY completed ASC,
CASE
WHEN completed = '0' THEN UNIX_TIMESTAMP(delivered) # ASC-ending
ELSE - UNIX_TIMESTAMP(delivered) # DESC-ending
END ASC
;
I need to query a table and gather counts with and without a column value.
What is the count of records that contain column value on 'src' and the count without.
Problem
Results contain one day only instead of every day on each row. Each row has same values.
Results Expected
DAY, CONTAINS VALUE, DOESN'T CONTAIN VALUE
Query
SELECT
DATE_FORMAT(edate,'%Y-%m-%d') as day,
(SELECT
COUNT(id) FROM entries WHERE src='a string' and color = 'red') with_value,
(SELECT
COUNT(id) FROM entries WHERE src='' and color = 'red') without_value
FROM entries
GROUP BY day
ORDER BY day DESC
You can do it without subqueryes using this technique:
SELECT
DATE_FORMAT(edate,'%Y-%m-%d') as day,
SUM(src = 'a string') as with_value,
SUM(src = '') as without_value
FROM entries
GROUP BY day
ORDER BY day DESC
What I did there was take advantage of the fact that MySQL does not have a Boolean data type, but rather TRUE is identical to 1, and FALSE to 0, in effect having the SUM act as a COUNT of rows that satisfy the condition.
I would do this using conditional aggregation:
SELECT DATE_FORMAT(edate, '%Y-%m-%d') as day,
SUM(src = 'a string' and color = 'red') as with_value,
SUM(src = '' and color = 'red') as without_value
FROM entries
GROUP BY day
ORDER BY day DESC;
In MySQL boolean expressions are treated as 0 (for false) and (1 for true) in an integer context. This makes them convenient for aggregation.
If you want per-day aggregate results then you need to perform the grouping by day in the query(-ies) where you compute the aggregate(s). You are grouping in a parent query instead.
In any event, you don't need subqueries for this, and it would be better to avoid them:
SELECT
DATE_FORMAT(edate,'%Y-%m-%d') as day,
SUM(CASE WHEN src='a string' THEN 1 ELSE 0 END CASE)
AS with_value
SUM(CASE WHEN src='' THEN 1 ELSE 0 END CASE)
AS without_value
FROM entries
WHERE color = 'red'
GROUP BY day
ORDER BY day DESC