MySQL insert comma delimited variable into multiple rows - mysql

I'm trying to create a stored procedure to quickly insert some data into my DB and just having a little trouble figuring out the quickest way to do this.
Into table one I insert a bunch of data about a file and return the new ID of that file.
I then have a separate table that tracks which versions of the app that file is compatible with.
This table has two columns
FileID, Version
Let's say the returned FileID = 1 in this instance.
The Version String will look like this
"1.1, 1.2, 2.1, 2.2"
Essentially I want to split that string and loop it so it ends up as 4 rows like this
FileID
Version
1
1.1
1
1.2
1
2.1
1
2.2

You can accomplish this goal with a little bit of creative splitting:
SELECT zz.`file_id`, zz.`word`
FROM (SELECT DISTINCT `file_id`, LOWER(TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX('1.1,1.2,1.3,2.0,2.1,2.1.5,2.2', ',', num.`id`), ',', -1))) as `word`
FROM (SELECT (h*1000+t*100+u*10+v+1) as `id`
FROM (SELECT 0 h UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) a,
(SELECT 0 t UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) b,
(SELECT 0 u UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) c,
(SELECT 0 v UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) d) num
WHERE num.`id` >= 0) zz
WHERE zz.`word` NOT IN ('')
ORDER BY zz.`word`;
This will give you up to 10,000 versions … if you need that many.

Related

Is there a less verbose mode to generating a set of numbers in mysql?

I often need to generate a range of IDs using a sequential number.
I use code like this ...
SELECT
numbers.value
FROM
(
SELECT
(((c3.d * 10) + c2.d) * 10) + c1.d value
FROM
(SELECT 0 d UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) c1,
(SELECT 0 d UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) c2,
(SELECT 0 d UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) c3
) numbers
WHERE
numbers.value BETWEEN 192 AND 264
This is then used in the context required.
Is there a less verbose way to do this?
If I was on MSSQL, then a CTE would be ideal. A function is also a possibility, but not exactly sure how to achieve that.
EDIT: I'm using mysql 5, so no WITH unfortunately.

mysql select odd number values in a column that includes delimiter separated values

My next database table will be set up more optimally. Unfortunately this one was already set up where one column [data] contains checkbox array values that were saved the following way:
value 1|~|value 1 value 2|~|value 2 value 3|~|value 3
Not optimal, I know.
What I need is a mysql query that select only the values in [data] column in front of the |~|. Basically think I need to select the only odd values.
Any help pointing me in the right direction is greatly appreciated. I tried an if statement in a query and it did not work. Of course I deleted that by mistake.
What I need is a mysql query that select only the
values in [data] column in front of the |~|.
One thing to note the numbers before |~| must be unique.
It will not show the same number twice.
Query
SELECT
DISTINCT
SUBSTRING (
record_data.column
, LOCATE('|~|', record_data.`column` , number_generator.number) - 1
, 1
) AS number
FROM (
SELECT
#row := #row + 1 AS number
FROM (
SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) record_1
CROSS JOIN (
SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) record_2
CROSS JOIN (
SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) record_4
CROSS JOIN (
SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) record_5
CROSS JOIN (
SELECT #row := 0
) AS init_user_params
) AS number_generator
CROSS JOIN (
SELECT
*
FROM (
SELECT 'value 1|~|value 1 value 2|~|value 2 value 3|~|value 3' AS `column`
) AS record
) AS record_data
WHERE
LOCATE('|~|', record_data.`column` , number_generator.number) <> 0
Result
| number |
| ------ |
| 1 |
| 2 |
| 3 |
demo

How do I create a MySQL function to output a query that has values from 1 to a given number?

I am bit new to MySQL. I am trying to create a mysql function that will produce and output a query with a single column with values from 1 to that given number.
Start of the function looks like,
create function get_NumberSequence (n)
Suppose I call the function as,
select get_NumberSequence(5);
I should get the output like below.
Sequence
--------
1
2
3
4
5
I tried an approach to combine and store queries like,
#num:=(select 1 as Sequence)
#num:=#num union (select 2 as Sequence)
This didn't work for me.
This is for case that your input number l_input_number < 10^4 (10000).
You could change your query with larger input number
SELECT #row := #row + 1 as sequence
FROM
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t2,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t3,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t4,
(SELECT #row:=0) t_init
LIMIT 17; --LIMIT l_input_number;
And use IF ELSE STATEMENT for each query of input number range for better performance
IF l_input_number < 1000
THEN --only use query up to t3
ELSEIF l_input_number < 10000
THEN --use query up to t4
ELSEIF l_input_number < 100000
THEN --use query up to t5
--etc........
END IF;

INSERT rows multiple times based on a column value from another table

Mainly, I would like to insert a row in table 1 multiple times, based on an integer value in a column of table 2.
My situation
Table 2 contains a column 'SKU' and 'stock', and I would like to insert the 'SKU' and a timestamp into table 1. I want this row duplicated for 'stock'-value times in table 1.
I currently have the following query:
DECLARE #Count int = 1
WHILE #Count <= ....
BEGIN
INSERT INTO table1 (table1.SKU, table1.timestamp_in)
SELECT table2.SKU, "some timestamp" FROM table2
SET ...
END
I am not sure if this is the correct approach. I would like to run this loop for 'table2.stock' times.
My question is: Is this possible with just a SQL query, or should it be a better practice to build some (in my case) java code for this?
You don't need a procedure or anything like that. All you need is a table containing just numbers. I'm creating this table on the fly with this in this example:
SELECT aa.a + 10*bb.b + 100*cc.c AS numbers FROM (
SELECT 0 a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) aa
, (SELECT 0 b UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) bb
, (SELECT 0 c UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) cc;
This creates the numbers 0 till 999.
Now you join your table2 with this numbers table in the range of stock. Your final query looks like this:
INSERT INTO table1 (table1.SKU, table1.timestamp_in)
SELECT table2.SKU, "some timestamp" FROM table2
INNER JOIN (
SELECT aa.a + 10*bb.b + 100*cc.c AS n FROM (
SELECT 0 a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) aa
, (SELECT 0 b UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) bb
, (SELECT 0 c UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) cc
) numbers ON numbers.n BETWEEN 0 AND table2.stock /*assuming you have no negative stock*/
Just make sure, that the numbers table contains more numbers than the highest value in the stock column.

Select the latest recored in each 2-minute interval in MySQL

I want to read about 8000 files, each containing the daily stock prices of a distinct stock, into a single table and select the latest price in each 2-minute interval and write a Null if no record available in an interval. My idea is add a column called bucketNumber to indicate which interval the record falls into, create another table containing one column of values 1, 2, ..., 195 repeating 8000 times and then joining the two tables. At last select the record with largest timestamps for records with the same bucketNumber.
Is this a good way to do the job? If it is, then how to efficiently generate a table with one column of values 1, 2, ..., 195 repeating 8000 times.
Here's a query that will return you a column of integer values from 1 to 8000
SELECT thousands.d*1000 + hundreds.d*100 + tens.d*10 + ones.d + 1 AS num
FROM ( SELECT 0 AS d UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
) ones
CROSS
JOIN ( SELECT 0 AS d UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
) tens
CROSS
JOIN ( SELECT 0 AS d UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
) hundreds
CROSS
JOIN ( SELECT 0 AS d UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
) thousands
HAVING num <= 8000
ORDER BY num
Seems like a stored procedure would be the easiest approach. Just loop through each 2 minute interval and select the price from the record having the maximum time in the interval. You could include arguments for the start and end time, which would provide a more general solution.