Order number and strings putting strings last - mysql

I am trying to make a SQL statement that selects and orders numbers in DESC but put all strings last
so mysql is:
"SELECT * FROM posts ORDER BY price DESC"
and that gives me something like
test
best offer
6000
100
10
what I want is:
6000
100
10
test
best offer
or (doesnt matter)
6000
100
10
best offer
test

SELECT * FROM posts
ORDER BY price * 1 DESC
SQLFiddle demo

I think want you actually want is:
SELECT * FROM t ORDER BY value ASC;
which returns:
10
100
6000
best offer
test
SQL Fiddle

If you generally do not care about performance, you can do something like this:
SELECT * FROM posts
ORDER BY
CASE CAST(price AS int) WHEN 0 THEN ' ' ELSE price END DESC,
price ASC;
You might need the casts to int depending on your database.
You can also fiddle with the first expression to get the results you want. The point is that you have to sort first by whether it's a number or not and then the actual content.
The problem is that this you can't use any indexes this way. If you are allowed to change the database structure, it would be better to split the data into two columns. An int column with the price and a varchar column with the price description (in which case the first column is NULL). Then you can do faster queries.

Related

How to group by with 2 different field for the below criteria

Name date sellingAmt
Raju 08-02-2017 2000
Ravi 09-02-2017 5000
Ravi 09-02-2017 2000
Raju 09-02-2107 1000
Expected Result
Name date sellingAmt
Raju 08-02-2017 2000
Ravi 09-02-2017 7000
Raju 09-02-2107 1000
Let me know how to group by this in mysql select query
Seems like a pretty basic question. What part are you struggling with?
Always post what you've tried so we can look at your train of thought and try to correct the problem at it's root instead of giving you a baked solution!
Date (and I just see name is as well) is a keyword/reserved word so out of habit I use the ` to escape them.
I used sellingAmt Desc as the order by since it appears you want those within the same date; though you could just as easily want name desc.
I group by name, date to achieve the desired results. While mySQL extends the group by so you can group on fewer values than what is in the select, I find this feature is wrongly used more often than correctly. So I tend to error on the side of caution and always group by all fields not part of an aggregate; which is what other RDBMS systems would require of you. In your case date and name are the unique combination to sum sellingAmt correctly and achieve your expected results.
.
SELECT `Name`, `Date`, Sum(SellingAmt) sellingAmt
FROM {tblName}
GROUP BY `Name`, `Date`
ORDER BY `date`, sellingAmt Desc
Replace {tblname} with your table name.

MySQL Sum and Case Query

I create a ReportViewer with VB.NET connecting to a MySQL database. The data appears like below.
IdProduct Quantity TotalPrice OrderDate
0001 1 10 29/09/2014
0002 2 40 29/09/2014
0001 4 40 29/09/2014
0001 2 20 29/09/2014
0001 2 20 29/09/2014
Based on the records above, I'd like the result to appear like below
0001 0002
9 2
90 40
What is Query Sum Case the best use here? Thanks in advance.
NOTE: It's not possible for a query to "dynamically" alter the number or datatype of the columns returned, those must be specified at the time the SQL text is parsed.
To return the specified resultset with a query, you could do something like this:
SELECT SUM(IF(t.IdProduct='0001',t.Quantity,NULL)) AS `0001`
, SUM(IF(t.IdProduct='0002',t.Quantity,NULL)) AS `0002`
FROM mytable t
UNION ALL
SELECT SUM(IF(t.IdProduct='0001',t.TotalPrice,NULL)) AS `0001`
, SUM(IF(t.IdProduct='0002',t.TotalPrice,NULL)) AS `0002`
FROM mytable t
Note that the datatypes returned by the two queries will need to be compatible. This won't be a problem if Quantity and TotalPrice are both defined as integer.
Also, there's no specific guarantee that the "Quantity" row will be before the "TotalPrice" row; we observe that behavior, and it's unlikely that it will ever be different. But, to have a guarantee, we'd need an ORDER BY clause. So, including an additional discriminator column (a literal in the SELECT list of each query), that would give us something we could ORDER BY.
Note that it's not possible to have this single query dynamically create another column for IdProduct '0003'. We'd need to add that to the SELECT list of each query.
We could do this in two steps, using a query to get the list of distinct IdProduct, and then use that to dynamically create the query we need.
BUT... with all that said... we don't want to do that.
The normative pattern would be to return Quantity and TotalPrice as two separate columns, along with the IdProduct as another column. For example, the result returned by this statement:
SELECT t.IdProduct
, SUM(t.Quantity) AS `Quantity`
, SUM(t.TotalPrice) AS `TotalPrice`
FROM mytable t
GROUP BY t.IdProduct
And then the client application would be responsible for transforming that resultset into the desired display representation.
We don't want to push that job (of transforming the result into a display representation) into the SQL.
select idproduct, sum(quantity), sum(totalprice)
from your_table
group by idproduct

Mysql select records with offset

I'm looking for a mysql select that will allow me to select (LIMIT 8) records after some changing number of first few matches;
select id
from customers
where name LIKE "John%"
Limit 8
So if i have a table with 1000 of johns with various last names
I want to be able to select records 500-508
You can send the offset to the limit statement, like this:
SELECT id
FROM customers
WHERE name LIKE "John%"
LIMIT 8 OFFSET 500
Notice the OFFSET 500 on the limit. That sets the 'start point' past the first 500 entries (at entry #501).
Therefor, entries #501, #502, #503, #504, #505, #506, #507 and #508 will be selected.
This can also be written:
LIMIT 500, 8
Personally, I don't like that as much and don't understand the order.
Pedantic point: 500-508 is 9 entries, so I had to adjust.
As a solution please try executing the following sql query
select id from customers where name LIKE "John%" Limit 500,8

Sum Of mysql table record

I have a table named tbl_Question and a column named INT_MARK which has different marks for different questions. Like this:
VH_QUESTION INT_MARK
----------- --------
Q1 2
Q2 4
My question is: How to get a random set of 20 questions whose total sum of marks is 50?
select VH_QUESTION, sum(INT_MARK) from tbl_Question
group by VH_QUESTION
having sum(INT_MARK) > 50
order by rand() limit 1
I think this question may help you - seems a very similar problem.
If that don't work, I'd try to divide the problem in two: first, you make a combinatory of your questions. Then, you filter them by it's sum of points.
I couldn't find, however, how to produce all combinations of the table. I don't know how difficult that would be.
select VH_QUESTION, sum(INT_MARK) from tbl_Question
group by VH_QUESTION
having sum(INT_MARK) >= 50
order by rand() limit 20
Quick answer
SELECT * ,SUM(INT_MARK) as total_mark FROM tbl_Question
GROUP BY VH_QUESTION
HAVING total_mark="50"
ORDER BY RAND()
LIMIT 5
it returns 0 line when no answers are possible but each time it finds one the questionsare random.
You could check the benchmark to see if you can have a faster query for large tables.

Weighted conditions in the WHERE clause of a SQL statement

I want to search for records where a particular field either STARTS WITH some string (let's say "ar") OR that field CONTAINS the string, "ar".
However, I consider the two conditions different, because I'm limiting the number of results returned to 10 and I want the STARTS WITH condition to be weighted more heavily than the CONTAINS condition.
Example:
SELECT *
FROM Employees
WHERE Name LIKE 'ar%' OR Name LIKE '%ar%'
LIMIT 10
The catch is that is that if there are names that START with "ar" they should be favored. The only way I should get back a name that merely CONTAINS "ar" is if there are LESS than 10 names that START with "ar"
How can I do this against a MySQL database?
You need to select them in 2 parts, and add a Preference tag to the results. 10 from each segment, then merge them and take again the best 10. If segment 1 produces 8 entries, then segment 2 of UNION ALL will product the remaining 2
SELECT *
FROM
(
SELECT *, 1 as Preferred
FROM Employees
WHERE Name LIKE 'ar%'
LIMIT 10
UNION ALL
SELECT *
FROM
(
SELECT *, 2
FROM Employees
WHERE Name NOT LIKE 'ar%' AND Name LIKE '%ar%'
LIMIT 10
) X
) Y
ORDER BY Preferred
LIMIT 10
Assign a code value to results, and sort by the code value:
select
*,
(case when name like 'ar%' then 1 else 2 end) as priority
from
employees
where
name like 'ar%' or name like '%ar%'
order by
priority
limit 10
Edit:
See Richard aka cyberkiwi's answer for a more efficient solution if there are potentially lots of matches.
My solution is:
SELECT *
FROM Employees
WHERE Name LIKE '%ar%'
ORDER BY instr(name, 'ar'), name
LIMIT 10
The instr() looks for the first occurrence of the pattern in question. AR% will come before xxAR.
This prevents:
Should only do table scan 1 time. Unions and derived tables do 3. The first two on the columns to filter out the patterns and then the 3rd on the subset to find where they equal - since union filters out dupes.
Gives a true sort based on the location of the pattern. Wx > xW > xxW > etc...
Try this (don't have a MySQL instance immediately available to test with):
SELECT * FROM
(SELECT * FROM Employees WHERE Name LIKE 'ar%'
UNION
SELECT * FROM Employees WHERE Name LIKE '%ar%'
)
LIMIT 10
There are probably better ways to do it, but that immediately sprang to mind.
SELECT *
FROM Employees
WHERE Name LIKE 'ar%' OR Name LIKE '%ar%'
ORDER BY LIKE 'ar%' DESC
LIMIT 10
Should work orders by the binary true / false for like and if index'ed should benefit from the index