ORDER BY two variable parts of a string - mysql

I'm stuck and don't know how to proceed further. How do I order my results accordingly?
10 x 2 ml
10 x 10 ml
4 x 20 ml
10 x 2 ml should come first because 2 ml is smaller than 10 ml.
And then order by the number that comes before the multiplication sign.

This is how I solved my own question:
ORDER BY SUBSTR(size, INSTR(size, 'x') + 2) + 0, size + 0

You could try this, but it's really ugly, especially if the tables are big and you need performance:
ORDER BY TRIM(REPLACE(REPLACE(field_name,CONCAT(SUBSTRING_INDEX(field_name,'x',1),'x'),''),'ml',''))
it replaces SUBSTRING_INDEX('ABCx123ml','x',1); //ABC and ml with blanks, triming it, leaving only the value needed for order...

Related

How do I get the b-complement of 193 for b = 5?

So I am supposed to find the b-complement for 193 given that b = 5 and the number of digits allowed is n = 6.
Now I think I am a bit confused regarding the b-complement in general.
Is it that whenever b is odd, just like in the case we have here, you are supposed to subtract 1 from the base and calculate the complement with the result?
If that's the case, you would calculate the 4-complement of 193, right?
But do I then also subtract the then found out number from 444444 or still 555555?

Efficiently joining over interval ranges in SQL

Suppose I have two tables as follows (data taken from this SO post):
Table d1:
x start end
a 1 3
b 5 11
c 19 22
d 30 39
e 7 25
Table d2:
x pos
a 2
a 3
b 3
b 12
c 20
d 52
e 10
The first row in both tables are column headers. I'd like to extract all the rows in d2 where column x matches with d1 and pos1 falls within (including boundary values) d1's start and end columns. That is, I'd like the result:
x pos start end
a 2 1 3
a 3 1 3
c 20 19 22
e 10 7 25
The way I've seen this done so far is:
SELECT * FROM d1 JOIN d2 USING (x) WHERE pos BETWEEN start AND end
But what is not clear to me is if this operation is done as efficient as it can be (i.e., optimised internally). For example, computing the entire join first is not really a scalable approach IMHO (in terms of both speed and memory).
Are there any other efficient query optimisations (ex: using interval trees) or other algorithms that can handle ranges efficiently (again, in terms of both speed and memory) in SQL that I can make use of? It doesn't matter if it's using SQLite, PostgreSQL, mySQL etc..
What is the most efficient way to perform this operation in SQL?
Thank you very much.
Not sure how it all works out internally, but depending on the situation I would advice to play around with a table that 'rolls out' all the values from d1 and then join on that one. This way the query engine can pinpoint the right record 'exactly' instead of having to find a combination of boundaries that match the value being looked for.
e.g.
x value
a 1
a 2
a 3
b 5
b 6
b 7
b 8
b 9
b 10
b 11
c 19 etc..
given an index on the value column (**), this should be quite a bit faster than joining with the BETWEEN start AND end on the original d1 table IMHO.
Off course, each time you make changes to d1, you'll need to adjust the rolled out table too (trigger?). If this happens frequently you'll spend more time updating the rolled out table than you gained in the first place! Additionally, this might take quite a bit of (disk)space quickly if some of the intervals are really big; and also, this assumes we don't need to look for non-whole numbers (e.g. what if we look for the value 3.14 ?)
(You might consider experimenting with a unique one on (value, x) here...)

Selecting rows if the total sum of a row is equal to X

I have a table that holds items and their "weight" and it looks like this:
items
-----
id weight
---------- ----------
1 1
2 5
3 2
4 9
5 8
6 4
7 1
8 2
What I'm trying to get is a group where the sum(weight) is exactly X, while honouring the order in which were inserted.
For example, if I were looking for X = 3, this should return:
id weight
---------- ----------
1 1
3 2
Even though the sum of ids 7 and 8 is 3 as well.
Or if I were looking for X = 7 should return
id weight
---------- ----------
2 5
3 2
Although the sum of the ids 1, 3 and 6 also sums 7.
I'm kind of lost in this problem and haven't been able to come up with a query that does at least something similar, but thinking this problem through, it might get extremely complex for the RDBMS to handle. Could this be done with a query? if not, what's the best way I can query the database to get the minimum amount of data to work with?
Edit: As Twelfth says, I need to return the sum, regardless of the amount of rows it returns, so if I were to ask for X = 20, I should get:
id weight
---------- ----------
1 1
3 2
4 9
5 8
This could turn out to be very difficult in sql. What you're attempting to do is solve the knapsack problem, which is non-trivial.
The knapsack problem is interesting from the perspective of computer science for many reasons:
The decision problem form of the knapsack problem (Can a value of at least V be achieved without exceeding the weight W?) is NP-complete, thus there is no possible algorithm both correct and fast (polynomial-time) on all cases, unless P=NP.
While the decision problem is NP-complete, the optimization problem is NP-hard, its resolution is at least as difficult as the decision problem, and there is no known polynomial algorithm which can tell, given a solution, whether it is optimal (which would mean that there is no solution with a larger, thus solving the decision problem NP-complete).
There is a pseudo-polynomial time algorithm using dynamic programming.
There is a fully polynomial-time approximation scheme, which uses the pseudo-polynomial time algorithm as a subroutine, described below.
Many cases that arise in practice, and "random instances" from some distributions, can nonetheless be solved exactly.

Limiting numbers to a maximum value in MySQL

Is there a built-in function or some other way to limit the value of numbers in MySQL?
For example, let's say I have a table with the following rows:
score
=====
5
10
20
50
3
15
I'd looking for some type of query along the lines of...
SELECT NUMBER_LIMITER(score, 10) FROM ScoresTable
...which would return the following result...
score
=====
5
10
10
10
3
10
If not, I'll write a function. Just hoping there might be something built-in as performance is quite important for this project. Thanks!
SELECT LEAST(score, 10) FROM ScoresTable
http://dev.mysql.com/doc/refman/5.5/en/comparison-operators.html#function_least

MySQL append , prefix a range of numbers with 0

I have around a few thousand rows with which contain 3 digit numbers starting with 100 and ranging to 199 which i need to prefix with 0. There are also thousands of other numbers 4 digit numbers as well which i don't want to change.
I need find all the 3 digit numbers in the range and prefix only those ranging from 100 -199 with a 0 so as they are 4 digits eg 100 > 0100 , 104 > 0104 and so on.
Also these numbers may step eg 110 next is 124.
Is there a way I can do this using SQL? as i don't fancy changing these manually!
Many Thanks
This is best done with a programming language. That said, here's a SQL query that will update all the existing numbers:
UPDATE tableName SET fieldName = right(concat('0000',fieldName), 4) WHERE length(fieldName) < 4
The LPAD function is what you are looking for. You can use this in your query to pad the numbers on the fly.
SELECT LPAD(CONVERT(num AS CHAR), 4, '0') FROM tbl WHERE num > 99 AND num < 200
If you prefer to do this on the script side, str_pad will do the same in php.