Mysql - splitting table contents, order amount and its description - mysql

I'm having a problem with a mysql query, i have a table which contains both the amount of an order (the first int in the table) and it's description. Unfortunately i cant change the database structure. I need to split these in a query, i have the following query;
Load table:
3 pallets 120 x 100 x 100
12 pallet 120 x 100 x 84
SELECT *,
IF (load * 1! = 0, LEFT (load, 1), '1 ') AS cargo_quantity,
IF (load * 1! = 0, SUBSTR (load, 2), load) AS cargo_description
FROM transport
The query works when the amount is below 10, when the number is 10 or higher the query will fall short. I could really use some help solving this problem, any suggestions?

If you are sure that the first "column" of your entry is always seperated by " " then you can do this:
SELECT *,
LEFT(loadcolumn, LOCATE(" ",loadcolumn)) AS cargo_quantity,
SUBSTR(loadcolumn, LOCATE(" ",loadcolumn)+1) AS cargo_description
FROM transport
and here a sqlfiddle with a working solution:
Note that "load" seems to be a mysql keyword. I am not sure, so in my sqlfiddle I renamed it.
EDIT:
here is the improved solution if your "first column" does not exist:
SELECT *,
IF (concat('',(LEFT(loadcolumn, LOCATE(" ",loadcolumn))) * 1) =
LEFT(loadcolumn, LOCATE(" ",loadcolumn)),
LEFT(loadcolumn, LOCATE(" ",loadcolumn)), '1') AS cargo_quantity,
IF (concat('',(LEFT(loadcolumn, LOCATE(" ",loadcolumn))) * 1) =
LEFT(loadcolumn, LOCATE(" ",loadcolumn)),
SUBSTR(loadcolumn, LOCATE(" ",loadcolumn)+1), loadcolumn) AS cargo_description
FROM transport
improved sqlfiddle

Related

How to get Random of two specific numbers?

E.g.
The first number is: 429
The second number is: 529
So I want to write MySQL query in such a way that, it should give me either 429 or 529 exactly.
I searched on google regarding this, but its showing results for a random number as a range.
Any help will be appreciated.
EDIT
My real requirement is this:
INSERT INTO table1(table2_id, status, stage, added_by)
(SELECT id, 'Pending', 'Semifinal', RAND(SELECT 429 UNION SELECT 529) FROM table2)
SELECT * FROM (SELECT 429 UNION SELECT 529) AS tmp ORDER BY RAND() LIMIT 1
Steps:
Select 429 and 529
Apply random order
Return first result
The function is the following (without UNION and ORDER, only math and only one step):
(ROUND(RAND()) * 100) + 429
or
(FLOOR(0 + (RAND() * 2)) * 100) + 429
Refer to MySQL docs
APPENDED
To give a general answer to the question (to select one random integer from any two integers :x and :y):
(FLOOR(0 + (RAND() * 2)) * (:y - :x)) + :x
This way does not create a mem table and does not sort the rows in it and/or fetch one of the random rows.
Is this data placed within a table? Then something like this might work:
SELECT number FROM table ORDER BY rand() LIMIT 1

SELECT on VIEW is slow

I'm trying to optimize an algoritmic query by using a view. I created the view like:
Simplified version:
CREATE ALGORITHM = MERGE VIEW view_name AS (SELECT field1, fiedl2, field 3,
FUNC1(1, 2) AS score1,
FUNC2(1, 2) AS score2,
FUNC3(1, 2) AS score3,
FUNC4(1, 2) AS score4
FROM table
WHERE field1 = 1
); # only 0.003 seconds - approximate 2000 records
But when I try to do a SELECT query like:
SELECT * FROM view_name
ORDER BY (score1 * 1 + score2 * 2 + score3 * 2 + score4 * 4) DESC
LIMIT 0,20; # 9 to 11 seconds
The query takes about 10 seconds to get up with the result.
I already tried a couple of other solutions, but nothing has succeeded, see:
MySQL query slow because of ORDER BY with Stored Functions
If anyone has a clue, suggestion or an answer that would be awesome!
Thanks!

MySQL query slow because of ORDER BY with Stored Functions

My query goes from 15 seconds to 0.05 seconds when I remove the ORDER BY in the following query:
simplified version:
SELECT field1, fiedl2, field 3,
FUNC1(1, 2) AS score1,
FUNC2(1, 2) AS score2,
FUNC3(1, 2) AS score3,
FUNC4(1, 2) AS score4
FROM table
WHERE field1 = 1
ORDER BY (score1 * 1 + score2 * 2 + score3 * 2 + score4 * 4) DESC;
I have a couple of stored functions that calculate sub-scores. Except I have to order the result based on the total score. In the ORDER BY I use * 2 to add some weight to the subscores to influence the total score.
I use MySQL 5.6.13
Has anybody has an idea how I can make the ORDER BY, but not slow it down?
Like is it possible to and store the score# fields and sum them up?
Thanks!
The difference in time is because MySql needs to create a sorted temp table and fill it with data. As your query is running much slower when using order by, the problem might be in disk where temp data is stored. You haven't mentioned how many rows you are returning from this query. You may also try manually perform the steps that MySql is probably doing, so create a temp table with primary key (order_by_result int, n int auto_increment) and insert into it your select results:
Insert into t(order_by_result, n, ...)
select (score1 * 1 + score2 * 2 + score3 * 2 + score4 * 4),null,...
and check hpw fast it runs - you may also check this way if the problem lies in your storage.
You could add a total_score column to the table, and define a trigger to update it automatically whenever a row is added or updated. Then index the column, and ORDER BY total_score should be fast.
I think the best solution is to precalculate the values of the functions and store them in the database. This way, the problem of calculating the values of the function on the fly will be transformed into a very simple ordering query.
As lowleveldesing has said, this type of queries forces mysql to calculate the product (score1 * 1 + score2 * 2 + score3 * 2 + score4 * 4) for all the register before giving you any output.

Select data which have same letters

I'm having trouble with this SQL:
$sql = mysql_query("SELECT $menucompare ,
(COUNT($menucompare ) * 100 / (SELECT COUNT( $menucompare )
FROM data WHERE $ww = $button )) AS percentday FROM data WHERE $ww >0 ");
$menucompare is table fields names what ever field is selected and contains data bellow
$button is the week number selected (lets say week '6')
$ww table field name with row who have the number of week '6'
For example, I have data in $menucompare like that:
123456bool
521478bool
122555heel
147788itoo
and I want to select those, who have same word in the last of the data and make percentage.
The output should be like that:
bool -- 50% (2 entries)
heel -- 25% (1 entry)
itoo -- 25% (1 entry)
Any clearness to my SQL will be very appreciated.
I didn't find anything like that around.
Well, keeping data in such format probably not the best way, if possible, split the field into 2 separate ones.
First, you need to extract the string part from the end of the field.
if the length of the string / numeric parts is fixed, then it's quite easy;
if not, you should use regular expressions which, unfortunately, are not there by default with MySQL. There's a solution, check this question: How to do a regular expression replace in MySQL?
I'll assume, that numeric part is fixed:
SELECT s.str, CAST(count(s.str) AS decimal) / t.cnt * 100 AS pct
FROM (SELECT substr(entry, 7) AS str FROM data) AS s
JOIN (SELECT count(*) AS cnt FROM data) AS t ON 1=1
GROUP BY s.str, t.cnt;
If you'll have regexp_replace function, then substr(entry, 7) should be replaced to regexp_replace(entry, '^[0-9]*', '') to achieve the required result.
Variant with substr can be tested here.
When sorting out problems like this, I would do it in two steps:
Sort out the SQL independently of the presentation language (PHP?).
Sort out the parameterization of the query and the presentation of the results after you know you've got the correct query.
Since this question is tagged 'SQL', I'm only going to address the first question.
The first step is to unclutter the query:
SELECT menucompare,
(COUNT(menucompare) * 100 / (SELECT COUNT(menucompare) FROM data WHERE ww = 6))
AS percentday
FROM data
WHERE ww > 0;
This removes the $ signs from most of the variable bits, and substitutes 6 for the button value. That makes it a bit easier to understand.
Your desired output seems to need the last four characters of the string held in menucompare for grouping and counting purposes.
The data to be aggregated would be selected by:
SELECT SUBSTR(MenuCompare, -4) AS Last4
FROM Data
WHERE ww = 6
The divisor in the percentage is the count of such rows, but the sub-stringing isn't necessary to count them, so we can write:
SELECT COUNT(*) FROM Data WHERE ww = 6
This is exactly what you have anyway.
The divdend in the percentage will be the group count of each substring.
SELECT Last4, COUNT(Last4) * 100.0 / (SELECT COUNT(*) FROM Data WHERE ww = 6)
FROM (SELECT SUBSTR(MenuCompare, -4) AS Last4
FROM Data
WHERE ww = 6
) AS Week6
GROUP BY Last4
ORDER BY Last4;
When you've demonstrated that this works, you can re-parameterize the query and deal with the presentation of the results.

MySQL: LIMIT by a percentage of the amount of records?

Let's say I have a list of values, like this:
id value
----------
A 53
B 23
C 12
D 72
E 21
F 16
..
I need the top 10 percent of this list - I tried:
SELECT id, value
FROM list
ORDER BY value DESC
LIMIT COUNT(*) / 10
But this doesn't work. The problem is that I don't know the amount of records before I do the query. Any idea's?
Best answer I found:
SELECT*
FROM (
SELECT list.*, #counter := #counter +1 AS counter
FROM (select #counter:=0) AS initvar, list
ORDER BY value DESC
) AS X
where counter <= (10/100 * #counter);
ORDER BY value DESC
Change the 10 to get a different percentage.
In case you are doing this for an out of order, or random situation - I've started using the following style:
SELECT id, value FROM list HAVING RAND() > 0.9
If you need it to be random but controllable you can use a seed (example with PHP):
SELECT id, value FROM list HAVING RAND($seed) > 0.9
Lastly - if this is a sort of thing that you need full control over you can actually add a column that holds a random value whenever a row is inserted, and then query using that
SELECT id, value FROM list HAVING `rand_column` BETWEEN 0.8 AND 0.9
Since this does not require sorting, or ORDER BY - it is O(n) rather than O(n lg n)
You can also try with that:
SET #amount =(SELECT COUNT(*) FROM page) /10;
PREPARE STMT FROM 'SELECT * FROM page LIMIT ?';
EXECUTE STMT USING #amount;
This is MySQL bug described in here: http://bugs.mysql.com/bug.php?id=19795
Hope it'll help.
I realize this is VERY old, but it still pops up as the top result when you google SQL limit by percent so I'll try to save you some time. This is pretty simple to do these days. The following would give the OP the results they need:
SELECT TOP 10 PERCENT
id,
value
FROM list
ORDER BY value DESC
To get a quick and dirty random 10 percent of your table, the following would suffice:
SELECT TOP 10 PERCENT
id,
value
FROM list
ORDER BY NEWID()
I have an alternative which hasn't been mentionned in the other answers: if you access from any language where you have full access to the MySQL API (i.e. not the MySQL CLI), you can launch the query, ask how many rows there will be and then break the loop if it is time.
E.g. in Python:
...
maxnum = cursor.execute(query)
for num, row in enumerate(query)
if num > .1 * maxnum: # Here I break the loop if I got 10% of the rows.
break
do_stuff...
This works only with mysql_store_result(), not with mysql_use_result(), as the latter requires that you always accept all needed rows.
OTOH, the traffic for my solution might be too high - all rows have to be transferred.