Loop unique insert into temporary table MySql stored procedure - mysql

I have two tables that look like this:
Table 1
Type 1 | Type 2 | Type 3 | ...
1 | 3 | 0 | ...
Table 2
Type 1 | Type 2 | Type 3 | ...
3 | 2 | 1 | ...
I would like to combine them into a temporary table like this:
Temporary Table
UID | Type | Table
1 | Type 1 | 1
2 | Type 2 | 1
3 | Type 2 | 1
4 | Type 2 | 1
7 | Type 1 | 2
8 | Type 1 | 2
9 | Type 1 | 2
10 | Type 2 | 2
11 | Type 2 | 2
Essentially, the numbers in tables 1 and 2 are totals and I want to break them out into individual rows in this temporary table.
I started going down the path of selecting from both tables and storing the values into temporary variables. I was then going to loop through every single variable and insert into the temporary table. But I have about 15 columns per table and there has got to be an easier way of doing this. I just don't know what it is.
Does anyone have any insight on this? My knowledge is incredibly limited on MySql stored procedures.

Not sure of an easy way to do this. One option would be to have a numbers table. Heres a quick approach to getting 1-10 in a common-table-expression (change as needed).
Then you could join to each table and each type, using union all for each subset. Here is a condensed version:
with numbers as (select 1 n 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 union all select 10)
select 'type1' as type, '1' as tab
from numbers n join table1 t on n.n <= t.type1
union all
select 'type2' as type, '1' as tab
from numbers n join table1 t on n.n <= t.type2
union all
select 'type1' as type, '2' as tab
from numbers n join table2 t on n.n <= t.type1
union all
select 'type2' as type, '2' as tab
from numbers n join table2 t on n.n <= t.type2
Demo Fiddle

Related

MySQL - select distinct value from two column

I have a table with the following structure:
IdM|IdS
-------
1 | 2
1 | 3
1 | 4
2 | 1
2 | 3
2 | 4
3 | 1
3 | 2
3 | 3
3 | 4
How could I make a select statement on this table, which will return some rows of this table, where in each row, a specific id appears only one, indifferent on which column it is specified?
For the above result set, I would like a query that would return:
-------
1 | 2
3 | 4
-------
To give another example, if you would omit the first row in the original dataset:
IdM|IdS
-------
1 | 3
1 | 4
2 | 1
2 | 3
2 | 4
3 | 1
3 | 2
3 | 3
3 | 4
the result set should be:
-------
1 | 3
2 | 4
-------
That's actually an interesting problem. If I follow you correctly, you want to iterate through the dataset and only retain rows where both values were never seen before. You could use a recursive query:
with recursive
data as (
select idm, ids, row_number() over(order by idm, ids) rn
from mytable
where idm <> ids
),
cte as (
select idm, ids, rn, 1 as to_keep , concat(idm, ',', ids) visited from data where rn = 1
union all
select d.idm, d.ids, d.rn,
(not find_in_set(d.idm, c.visited) and not find_in_set(d.ids, c.visited)),
case when (not find_in_set(d.idm, c.visited) and not find_in_set(d.ids, c.visited))
then concat_ws(',', c.visited, d.idm, d.ids)
else c.visited
end
from cte c
inner join data d on d.rn = c.rn + 1
)
select idm, ids from cte where to_keep
The first CTE enumerates the rows ordered by both columns. Then the recursive query walks the resultset, checks if both values are new, and sets a flag accordingly of the columns. Flagged numbers are retained to be used for filtering in the following iteration.
Demo on DB Fiddle
Note that, given your requirement, not all values may appear in the resultset. Consider the following dataset:
idm ids
+-----+---
1 2
1 3
1 4
Your logic will only return the first row.

Select data from single column as multiple record

I have the following table structure in a mysql database.
id | files | status
1 a.pdf,b.pdf,c.pdx 1
2 d.pdf,e.pdf.g.pdf 2
3 x.pdf,k.pdf,y.pdf 1
As you can see, the attachments are all stored on a single line.
My query is supposed to select all rows where status = 1 so i'm expecting the data in the following format.
1 1 a.pdf 1
2 1 b.pdf 1
3 1 c.pdf 1
4 3 x.pdf 1
5 3 k.pdf 1
6 3 y.pdf 1
Unfortunately, I am unsure which operator I can use to accomplish this. I'm aware SQL has pivot but i doubt even that can address my issue.
As a result, I would appreciate if I could get any help in the condition of the select query.
Regards
Try this:
SET #row_num = 0;
SELECT
(#row_num := #row_num + 1) ROW_NUM,
id,
SUBSTRING_INDEX(SUBSTRING_INDEX(files, ',', idx), ',', -1) FileName,
status
FROM
test
JOIN
(SELECT 1 idx UNION ALL SELECT 2 idx UNION ALL SELECT 3 idx UNION ALL SELECT 4 idx UNION ALL SELECT 5 idx) idxs
on idxs.idx - 2 < LENGTH(files) - LENGTH(REPLACE(files, ",", ""))
WHERE status = 1
;
Just add as many indexes as your max count of files in a string.
Note that there should be no comma fater last filename. This is magic -2 is responsible for.
Consider the following...
I have a table (ints) of integers (0-9)...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id SERIAL PRIMARY KEY
,files VARCHAR(100) NOT NULL
,status INT NOT NULL
);
INSERT INTO my_table VALUES
(1,'a.pdf,b.pdf,c.pdx',1),
(2,'d.pdf,e.pdf,g.pdf',2),
(3,'x.pdf,k.pdf,y.pdf',1);
SELECT DISTINCT id
, SUBSTRING_INDEX(SUBSTRING_INDEX(files,',',i2.i*10+i1.i+1),',',-1) file
, status
FROM my_table
, ints i1
, ints i2
WHERE status = 1
ORDER
BY id, i2.i*10+i1.i;
+----+-------+--------+
| id | file | status |
+----+-------+--------+
| 1 | a.pdf | 1 |
| 1 | b.pdf | 1 |
| 1 | c.pdx | 1 |
| 3 | x.pdf | 1 |
| 3 | k.pdf | 1 |
| 3 | y.pdf | 1 |
+----+-------+--------+

Find rows without corresponding second row in MySQL

Given the following table:
type | area | shelf
-----|------|------
1 | a | 5
2 | a | 5
2 | a | 6
1 | a | 7
2 | a | 7
1 | b | 3
An area / shelf combination entry with type 2 always needs a corresponding entry with type 1. Type 1 can exist on its own (e.g. last row).
How can I find orphan type 2 rows (rows with type 2 without corresponding row with type 1) such as the third row?
You can do this with aggregation and a having clause:
select shelf, area
from t
group by shelf, area
having sum(type = 2) > 0 and -- at least one type 2
sum(type = 1) = 0; -- no type 1
Are you looking for this..
SELECT t2.*
FROM yourtable t1
RIGHT JOIN yourtable t2 ON t1.area = t2.area
AND t1.shelf=t2.shelf
AND t1.`type`=1
AND t2.`type`=2
WHERE t1.`type` IS NULL

MySQL missing values from column

Radio_ID | Log_ID
-----------------
1 | 1
1 | 2
1 | 4
1 | 7
1 | 10
2 | 1
2 | 2
2 | 3
2 | 5
Is it possible to get the following output in a single sql statement?
Output:
Radio_ID | Log_ID
-----------------
1 | 3
1 | 5
1 | 6
1 | 8
1 | 9
2 | 4
Logic: returns missing values for each id < max value for id (ex 10 is max value for radio id 1 and missing values are 3,5,6,8,9).
I have a data parser for a radio device and when the radio is outside the coverage area it doesn't send data, so I have to send a new request for missing Log_IDs.
Thank you!
Let me assume that you have a table called numbers with integers of a sufficient range.
Then you can do:
select r.radio_id, n.n as MissingLogId
from (select radio_id, min(log_id) as minli, max(log_id) as maxli
from table t
group by radio_id
) r join
numbers n
on n.n between r.minli and r.maxli left join
table t
on t.radio_id = r.radio_id and t.log_id = n.n
where t.radio_id is null;
The idea is to generate all the numbers for each radio id (between the minimum and maximum id) using a join. Then existing values are filtered out.
If you don't have a numbers table handy, you need to create one large enough. This would probably work:
create table numbers (n int primary key);
insert into numbers(n)
select (#rn := #rn + 1) as n
from table cross join (#rn := 0);

mysql select table where number of rows depends on dynamic values in two columns

I have a MySQL table:
id | style | minsize_id | maxsize_id
-------------------------------------
1 | Jacket | 1 | 3
2 | Pant | 2 | 4
3 | Hoody | 0 | 3
I would like to show an extra row for each size id between and including the minsize_id and maxsize_id (sizes can be any integer between 0 and 9), and a new column 'size_id' as follows:
id | style | size_id
----------------------
1 | Jacket | 1
1 | Jacket | 2
1 | Jacket | 3
2 | Pant | 2
2 | Pant | 3
2 | Pant | 4
3 | Hoody | 0
3 | Hoody | 1
3 | Hoody | 2
3 | Hoody | 3
How do I display the table in this way using only MySQL? Thanks for any help.
One way this could be achieved is to join this table onto a derived table which contains 10 rows, one for each size. For example
SELECT
yt.id,
yt.style,
sizes.size_id
FROM yourTable AS yt
INNER JOIN (
SELECT 0 AS size_id
UNION ALL
SELECT 1 AS size_id
UNION ALL
SELECT 2 AS size_id
UNION ALL
SELECT 3 AS size_id
UNION ALL
SELECT 4 AS size_id
UNION ALL
SELECT 5 AS size_id
UNION ALL
SELECT 6 AS size_id
UNION ALL
SELECT 7 AS size_id
UNION ALL
SELECT 8 AS size_id
UNION ALL
SELECT 9 AS size_id
) AS sizes
ON sizes.size_id BETWEEN yt.minsize_id AND yt.maxsize_id
If however you have a table "sizes" with primary key "size_id" then you can just INNER JOIN that instead of this derived table. Obviously replace yourTable and alias yt with whatever table name / alias you desire.
Here's one way:
SELECT id, style, size_id
FROM origTable ot
JOIN
(SELECT #rownum := #rownum + 1 AS size_id
FROM origTable ot1
CROSS JOIN origTable ot2,
(SELECT #rownum := -1) r) s
ON ot.minsize_id <= s.size_id AND ot.maxsize_id >= s.size_id
ORDER BY id, style, size_id
It may look a little messy at first glance but I'll try and explain:
MySQL doesn't have a row_number function like SQL Server does so I'm using a technique described here to artificially create this in the subquery (s). To create a lot of row numbers there needs to be a lot of rows in this so you could either choose a different table that already has a lot of rows or as I've done just do a CROSS JOIN of your original table - CROSS JOINs generally ends up with a lot of rows. Bit of a hack I know and may have degrading performance if origTable becomes large!
We need the row numbers to start at zero and what is selected by the subquery is pre-incremented by 1, hence the initialisation of #rownum to -1.
See SQL Fiddle Demo.